情景A
A1。写入易失性变量
A2。刷新所有本地非易失性变量写入主存储器
情景B
B1。从易变变量中读取
B2。将所有非易失性变量从主存储器重新加载到本地存储器
(使用Java 1.8 / 1.5 +)
答案 0 :(得分:2)
实际规则是“写入易失性变量 v (§8.3.1.4)与 v 的所有后续读取同步任何线程(根据同步顺序定义“后续”)。“ http://docs.oracle.com/javase/specs/jls/se8/html/jls-17.html#jls-17.4
换句话说,从一个线程写入到v
的写入一旦在该写入之后读取v
,就会对另一个线程的读取都可见。
我不确定“冲到主要”是理解这一点的必要方式。 Java内存模型以发生在之前和与同步的方式记录。我建议用这些术语来考虑它。从概念上讲,如果JVM不是必需的,那么它可以省略某些“刷新”。
答案 1 :(得分:2)
写入易失性变量不保证刷新非易失性变量 1 。但是,它会在写入易失性和随后的易失性读取之间引入“先发生”关系(假设没有中间写入)。您可以按如下方式利用它:
如果动作按此顺序发生,则线程B将在步骤4中看到NV的更新值。但是,如果在步骤2之后某些内容(包括A)写入NV,则未指定线程B将在步骤4中看到的内容
一般来说,以这种方式使用挥发物需要深入细致的推理。使用synchronized
更容易,更健壮。
你的例子不清楚:
如果要描述Java程序员必须做什么,那就错了/荒谬。 Java代码无法刷新变量。
如果要在实现级别(例如在JIT编译的代码中)指定必须的内容,那么它也是错误的。
如果想要描述可以在实现级别发生的事情(例如在JIT编译的代码中),那就是正确的。
我不只是在这里迂腐。编译器可能会认为它不需要刷新线程A中的所有本地非易失性,并且它很可能只会重新加载它在线程B中所需的那些。它如何决定?这是编译器编写者的业务!
1 - JLS不需要特定于硬件的操作,例如刷新。相反,它需要编译的代码满足一些特定的内存可见性保证,并将实现留给编译器编写器。