易失性保证安全发布可变对象?

时间:2016-10-18 21:59:51

标签: java multithreading concurrency volatile safe-publication

阅读实践中的Java并发

我可以看到:

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

  • 从静态初始值设定项初始化对象引用
  • 将对它的引用存储到易失性字段或AtomicReference
  • 将对它的引用存储到正确构造的对象的最终字段中
  • 将对它的引用存储到由a正确保护的字段中 锁。

然而,我对第二个成语感到困惑。由于volatile只能保证引用对另一个线程可见,但它不会同步对象构造(它引用)。那么如何保证可变对象被正确构造,构造该对象的线程被另一个线程中断了?

3 个答案:

答案 0 :(得分:6)

我们需要证明构造一个对象并将其分配给一个volatile变量是在从该变量中读取之前发生的。

From JLS Chapter 17:

  

如果 x y 是同一个线程的操作, x 按照程序顺序出现在 y 之前,然后 hb(x,y)。

因此,对象的构造发生在之前,从该线程的角度将分配给易变量

  

如果某个操作 x与同步 y,,那么我们还有 hb(x,y)。

  

如果 hb(x,y) hb(y,z),那么 hb(x,z)。

如果我们可以证明写入volatile变量(action y 同步 - 读取变量(action z ),我们可以使用发生在之前的传递性来表明构造对象(action x 读取对象之前发生。幸运的是:

  

写入易失性变量 v (§8.3.1.4)与任何线程同步 v 的所有后续读取(其中) “后续”是根据同步顺序定义的。

因此,我们可以看到,当以这种方式发布时,任何线程都可以看到正确构造的对象。

答案 1 :(得分:1)

Reads and writes are atomic for all variables declared volatile (including long and double variables).

结果:volatile保证变量总是从所有线程共享的内存中读取 - 如果值发布在volatile变量中,则必须之前是完全构造的。
换句话说,如果没有公布volatile值,那么没有其他线程会知道它 - 很可能是正在构建的结果&#39 ;可以驻留在CPU缓存中或JVM使用的内存中,作为我自己的目的使用的空间;你讨厌Java代码,不要问它里面有什么,它不是你的业务"。

答案 2 :(得分:1)

  

volatile只能保证引用对另一个线程是可见的,但它没有引用它所引用的对象构造的同步。

是。你是对的。您可以在下面的问题中找到有关volatile变量的内部细节的更多详细信息:

Difference between volatile and synchronized in Java

  

那么如何保证可变对象被正确构造,构造该对象的线程被另一个线程中断了什么呢?

您必须使用其他编程结构来实现线程安全:使用synchronized构造或synchronized构造的替代。

请参阅以下相关的SE问题:

Avoid synchronized(this) in Java?