Java线程安全性中的对象发布和逸出

探讨Java并发编程中的对象发布与逸出问题,分析常见错误代码示例,如对象引用过早暴露导致线程安全性破坏,以及如何通过安全发布方法避免此类问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      发布(Publish)和逸出(Escape)是Java并发编程中需要注意的问题。
      “发布”,简单来说就是提供一个对象的引用给作用域之外的代码。比如return一个对象,或者作为参数传递到其他类的方法中。
      “逸出”,是指如果一个类还没有构造结束就已经提供给了外部代码一个对象引用即发布了该对象,此时叫做对象逸出,对象的逸出会破坏线程的安全性。

      下面代码是我们经常编写的代码,states变量是一个私有变量,然而getStates()方法将states对象发布,states逃出了其作用域,这样其他类或对象就可以修改该对象:

@Slf4j
public class UnsafePublish {

    private String[] states = {"a", "b", "c"};

    public String[] getStates() {
        return states;
    }

    public static void main(String[] args) {
        UnsafePublish unsafePublish = new UnsafePublish();
        log.info("{}", Arrays.toString(unsafePublish.getStates()));

        unsafePublish.getStates()[0] = "d";
        log.info("{}", Arrays.toString(unsafePublish.getStates()));
    }
}

      运行代码输出:

[a, b, c]
[d, b, c]

      还有更加隐秘的this逸出,代码如下:

@Slf4j
public class Escape {

    private int thisCanBeEscape = 0;

    public Escape () {
        new InnerClass();
    }

    private class InnerClass {

        public InnerClass() {
            log.info("{}", Escape.this.thisCanBeEscape);
        }
    }

    public static void main(String[] args) {
        new Escape();
    }
}

      在上述代码中,在Escape的构造函数中相当于创建了一个线程,创建了一个内部类对象,内部类里面使用thisCanBeEscape,有可能在对象还没有发布完成就先使用了,有可能导致this引用在构造过程中逸出,这种对象也因此被认为是不正确构造。

      如果要在构造器中创建线程,应该使用专有的start或初始化的方法来统一启动线程,例如可以使用工厂方法和私有构造函数来完成对象的创建和监听器的创建。

     

      安全发布对象4种方法:

  • 在静态初始化函数中初始化一个对象引用
  • 将对象的引用保存到volatile类型域或者AtmoicReference对象中
  • 将对象的引用保存到某个正确构造对象的final类型域中
  • 将对象的引用保存到一个由锁保护的域中
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值