是写入 Java 中的易失性内存屏障

2022-09-01 19:09:56

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


答案 1

是的,它会启动一个障碍。您可以在此处阅读更多内容。有4种类型,LoadLoadLoadStore StoreStore StoreLoad。

至于你的问题

从 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)
}

答案 2

易失性变量和其他变量的引用是正确的。我没有意识到发生之前的传递性是必须由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 的写入和随后读取起到了内存屏障的作用。


推荐