最终与波动的保证书,以安全发布对象

Gee*_*eek 16 java java-memory-model

从Java并发实践中的书:

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

  • 从静态初始化程序初始化对象引用

  • 将对它的引用存储到volatile字段或AtomicReference中

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

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

我的问题是:

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

ass*_*ias 12

子弹点2和3之间有什么区别?

  • volatile基本上意味着对该字段的任何写入都将从其他线程中可见.因此,当您将字段声明为volatile:时private volatile SomeType field;,可以保证如果构造函数写入该字段:field = new SomeType();此随后尝试读取的其他线程将显示此分配field.
  • final具有非常相似的语义:您可以保证如果您有一个final字段:private final SomeType field;写入该字段(在声明或构造函数中):field = new SomeType();将不会被重新编码并且如果对象正确则将被其他线程看到发表(this例如,没有逃脱).

显然,主要的不同之处在于,如果该字段是最终的,则只能分配一次.

在第3点中,正确构造的物体的最终场是什么意思?

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


举例:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果在构造之后我更改了由诸如field.setX(new X())之类的字段所引用的对象的状态,那么当我们将其声明为volatile时,是否也保证其他线程可以看到该更改?还是仅提供初始化安全性?那么在这种情况下final呢? (2认同)