25

我最近在一次演讲中听说,对 volatile 的写入会触发线程写入的每个变量的内存屏障。这真的正确吗?从 JLS 来看,似乎只有相关变量被清除,而其他变量则没有。有人知道什么是正确的吗?可以指出我在 JLS 中的具体位置吗?

4

2 回答 2

28

是的,它会引发障碍。你可以在这里阅读更多。有4种类型,LoadLoad LoadStore StoreStore StoreLoad。

至于你的问题

从 JLS 来看,似乎只有相关变量被清除,而其他变量则没有。有人知道什么是正确的吗?

任何其他线程都可以看到在 volatile 存储之前发生的所有写入,前提是其他线程加载此新存储。但是,如果其他线程未加载新值,则在 volatile 加载之前发生的写入可能会或可能不会被其他线程看到。

举一个实际的例子

volatile int a =0;
int b = 0;

Thread-1
b = 10;
a = 3;

Thread-2
if(a == 0){
  // b can b 10 or 0
} 
if(a == 3){
   // b is guaranteed to be 10 (according to the JMM)
}
于 2012-12-03T17:45:19.130 回答
3

可变变量和其他变量的引用是正确的。我没有意识到happens-before的传递性是必须由VM实现的,而不是从定义中得出的。我仍然感到困惑,为什么没有明确说明具有如此深远影响的事物,而实际上是某种定义的推论。总结一下:假设您有 4 个这样的操作:

thread1        thread2
a1
a2
                a3
                a4

其中 a2 是对 volatile 变量 v 的写入,a3 是从同一个 volatile 变量 v 中读取。它遵循happens-before (hb) 的定义,即 hb(a1,a2) 和 hb(a3,a4)。此外,对于挥发物,我们有 hb(a2,a3)。现在从 hb 所需的传递性得出 hb(a1,a3)。因此,对 volatile 变量 v 的写入和后续读取起到了内存屏障的作用。

于 2012-12-04T07:48:33.830 回答