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

Gui*_* Li 7 java concurrency multithreading volatile safe-publication

通过阅读Java Concurrency in Practice

我可以看到:

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

  • 从静态初始化程序初始化对象引用
  • 将对它的引用存储到volatile字段或AtomicReference中
  • 将对它的引用存储到正确构造的对象的最终字段中
  • 将对它的引用存储到由锁正确保护的字段中.

但是,我对第二个成语感到困惑.因为volatile只能保证引用对另一个线程可见,它没有引用的对象构造的同步.那么如何保证可变对象被正确构造,构造该对象的线程被另一个线程中断了?

eri*_*son 9

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

来自JLS第17章:

如果xy是同一个线程的动作,并且x在程序顺序中出现在y之前,那么hb(x,y).

因此,从该线程的角度来看,在将对象分配给volatile变量之前,对象的构造就会发生.

如果动作x与后续动作y 同步,那么我们也有hb(x,y).

和:

如果是hb(x,y)hb(y,z),那么hb(x,z).

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

对易失性变量v(第8.3.1.4节)的写入与任何线程对v的所有后续读取同步(其中"后续"根据同步顺序定义).

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


Adr*_*chi 2

对于所有声明的变量volatile(包括longdouble变量),读取和写入都是原子的。

结果:volatile除其他外,保证变量始终从所有线程共享的内存中读取 - 如果值在变量中发布volatile,则必须在之前完全构造它。
换句话说,如果一个volatile值没有发布,那么其他线程不会知道它 - 最有可能的是“正在进行的构造”的结果可能驻留在 CPU 缓存中或 JVM 用作“我正在使用的空间”的内存中为了我自己的目的;你是微不足道的 Java 代码,别问里面有什么,这不关你的事”。