在Java中,对易失性数据的写入是内存障碍吗

在Java中,对易失性数据的写入是内存障碍吗,java,concurrency,volatile,jls,Java,Concurrency,Volatile,Jls,我最近在一次演讲中听说,对volatile的写入会触发线程写入的每个变量的内存屏障。这是真的吗?从JLS来看,似乎只有相关变量被清除,而其他变量则没有。有人知道什么是正确的吗?可以为我指出JLS中的具体位置吗?是的,它将启动屏障。你可以读更多。有4种类型,Load Load Store Store Load 至于你的问题 从JLS来看,似乎只有相关变量被刷新 是的,但不是其他人。有人知道什么是正确的吗 在易失性存储之前发生的所有写操作都可以被任何其他线程看到,并使用其他线程加载此新存储的谓词。但

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

是的,它将启动屏障。你可以读更多。有4种类型,Load Load Store Store Load

至于你的问题

从JLS来看,似乎只有相关变量被刷新 是的,但不是其他人。有人知道什么是正确的吗

在易失性存储之前发生的所有写操作都可以被任何其他线程看到,并使用其他线程加载此新存储的谓词。但是,如果其他线程不加载新值,则在易失性加载之前发生的写操作可能会被其他线程看到,也可能不会被其他线程看到

举个实际例子

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)
}
对的引用是正确的。我没有意识到,before的传递性是必须由VM实现的,而不是根据定义实现的。我仍然感到困惑的是,为什么一些具有如此深远影响的事物没有被清楚地表述出来,而实际上是某种定义的必然结果。总结一下:假设您有4个这样的操作:

thread1        thread2
a1
a2
                a3
                a4
其中a2是对易失性变量v的写入,a3是对同一易失性变量v的读取。 根据hb之前发生的定义,hb(a1,a2)和hb(a3,a4)。
同样,对于挥发物,我们有hb(a2,a3)。现在,根据hb的传递性,可以得出hb(a1,a3)。因此,易失性变量v的写入和随后的读取起到了内存屏障的作用。

我对JLS的解释与你的一致。可能的重复正如答案所阐明的,不只是声明为易失性的变量,而是在易失性写入之前发生的所有写入。+1“使用其他线程加载此新存储的谓词”我认为您的示例是错误的。线程2不需要将
a
与3进行比较以查看
b
的新值,读取
a
就足够了。因此,在第一行之后,线程2保证看到
b
等于10(在所有分支中)但是,第三个线程从不读取
a
并不能保证看到
b
@PhilippWendler的新值。我想问题是:如果a==0,那么写入
a=3
还没有发生,而b可以是任何东西,包括10。如果a==3,写入
a=3
已经发生,并且保证b==10。Shouldn这不是可以用一个更好的代码图来澄清吗?显示代码旁边的时间?例如,t=0,t=1,t=2,t=3…@assylias哪一个是正确的?根据JLS,Philipp的评论似乎是正确的。如果不是,请指出JLS中正确的句子。我的理解是==0语句肯定会加载/看到as 3,这是新的从这一点开始,将b存储为10。