最终与挥发性担保 w.rt 到对象的安全发布

2022-09-01 16:11:32

摘自《Java并发实践》一书:

若要安全地发布对象,必须同时使对该对象的引用和该对象的状态对其他线程可见。正确构造的对象可以通过以下方式安全地发布:

  • 从静态初始值设定项初始化对象引用

  • 将对它的引用存储到易失性字段或原子引用中

  • 将对它的引用存储到正确构造的对象的最终字段中

  • 将对它的引用存储到由
    锁正确保护的字段中。

我的问题是:

  1. 项目符号 2 和 3 之间有什么区别?我对方法和方法在对象的安全发布方面的区别感兴趣。volatilefinal
  2. 他在第3点中正确构造的对象的最终场是什么意思?在开始项目符号点之前,作者已经提到他们正在谈论一个正确构造的对象(我假设这是不让引用转义)。但是,他们又一次提到正确构造的对象呢?this

答案 1

项目符号 2 和 3 之间有什么区别?

  • volatile基本上意味着对该字段的任何写入都将从其他线程中可见。因此,当您将字段声明为 volatile: 时,可以保证,如果构造函数写入该字段:,则此赋值将被随后尝试读取 的其他线程可见。private volatile SomeType field;field = new SomeType();field
  • final具有非常相似的语义:您可以保证,如果您有最终字段:对该字段的写入(在声明中或在构造函数中):不会被重新odered,并且如果对象正确发布(即没有转义),则其他线程将可见(例如,没有转义)。private final SomeType field;field = new SomeType();this

显然,主要区别在于,如果字段是最终字段,则只能分配一次。

他在第3点中正确构造的对象的最终场是什么意思?

例如,如果您允许从构造函数中转义,则最终语义提供的保证将消失:观察线程可能会看到具有其默认值的字段(对于 Object 为 null)。如果对象构造正确,则不会发生这种情况。this


人为示例:

class SomeClass{
    private final SomeType field;

    SomeClass() {
        new Thread(new Runnable() {
            public void run() {
                SomeType copy = field; //copy could be null
                copy.doSomething(); //could throw NullPointerException
            }
        }).start();
        field = new SomeType();
    }
}

答案 2

发布与 的效果没有区别,除了只能在构造函数中设置一次,因此您阅读的内容永远不会更改。volatilefinalfinal

我相信一个正确构造的对象确实是你所指的,一个对象,它的引用没有逃脱其构造函数,并且已经以安全的方式发布到使用它的线程中。this


推荐