场景A
A1。写入 volatile 变量
A2。刷新所有本地非 volatile 变量写入到主内存
场景 B
B1。从 volatile 变量中读取
B2。将所有非 volatile 变量从主存重新加载到本地内存
- 场景 A 和 B 是涉及 volatile 的正确行为吗 变量?或者场景A是否也包含B2,或者场景B是否也包含 还包括A2?
- 这些场景是原子的吗?会不会有其他事情发生 在A1和A2之间?还是 B1 和 B2?
(使用 Java 1.8/1.5+)
最佳答案
写入 volatile 变量不保证刷新非 volatile 变量1。但是,它会在对 volatile 的写入和对 volatile 的任何后续读取之间引入“发生在之前”的关系(假设没有对其进行干预写入)。您可以按如下方式利用它:
- 线程A:写NV
- 线程A:写入V
- 线程 B : 读取 V
- 线程 B : 读取 NV
如果操作按该顺序发生,则线程 B 将在步骤 4 中看到 NV 的更新值。但是,如果某些东西(包括 A)在步骤 2 之后写入 NV,则线程 B 将在步骤 4 中看到什么是不确定的.
一般来说,以这种方式使用 volatiles 需要深入而仔细的推理。使用 synchronized
更容易也更健壮。
你的例子不清楚:
如果它旨在描述 Java 程序员必须做什么,那是错误的/荒谬的。 Java 代码不能刷新变量。
如果它旨在成为在实现级别(例如在 JIT 编译代码中)必须发生的事情的规范,那也是错误的。
如果它旨在描述在实现级别(例如在 JIT 编译代码中)可能发生的事情,那么它是正确的。
我不只是在这里学究气。编译器可能会决定它不需要刷新线程 A 中的所有 局部非 volatile 变量,并且它很可能只会重新加载它在线程 B 中需要的那些。它是如何决定的?那是编译器作者的事!
1 - JLS 不需要硬件特定的操作,例如刷新。相反,它要求编译后的代码满足一些特定的内存可见性保证,并将实现留给编译器编写者。
关于Java volatile变量影响其他非volatile变量的内存一致性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43712673/