cpu已经通过一些协议(比如mesi)保证了缓存的一致性。为什么我们还需要 volatile 在某些语言(如java)中保持多线程之间的可见性。可能的原因是这些协议在引导时没有启用,必须由一些指令触发,比如 LOCK .如果真是这样,为什么启动时cpu不启用协议?
volatile
LOCK
jutyujz01#
volatile可防止两种不同的问题:能见度重新排序我假设x86。。首先,x86上的缓存总是一致的。因此,在一个cpu将某个变量的存储提交到缓存之后,另一个cpu仍然会加载该变量的旧值,这是不可能的。这是mesi协议的域。假设java字节码中的每一个put和get都被翻译(而不是优化)到一个存储和cpu上的一个负载,那么即使没有volatile,每一个get都会看到同一个地址上最近的put。这里的问题是编译器(在本例中是jit)在优化代码方面有很大的自由度。例如,如果它检测到在循环中读取了相同的字段,它可以决定将该变量从循环中提升出来,如下所示。
for(...){ int tmp = a; println(tmp); }
吊装后:
int tmp = a; for(...){ println(tmp); }
如果该字段仅被1个线程触及,则这是很好的。但是如果字段被另一个线程更新,第一个线程将永远看不到更改。使用volatile可以防止此类可见性问题,这实际上是:c型挥发性jsr-133引入java内存模型之前的java volatile。具有不透明访问模式的varhandle。还有另一个非常重要的方面就是易变性;volatile防止对某些cpu执行的指令流中不同地址的加载和存储进行重新排序。jit编译器和cpu有很大的自由来重新排序加载和存储。尽管在x86上,由于存储缓冲区的原因,只有较旧的存储可以用较新的加载重新排序到不同的地址。想象一下下面的代码:
int a; volatile int b; thread1: a=1; b=1; thread2: if(b==1) print(a);
事实上 b 是挥发性的防止储存 a=1 在商店后面跳 b=1 . 它还可以防止 a 在…之前跳进去 b . 这样线程2就可以看到 a=1 ,当它读到 b=1 .因此,使用volatile,可以确保非volatile字段对其他线程可见。如果您想了解volatile是如何工作的,我建议您深入研究java内存模型,它是用synchronize with表示的,发生在margeret bloom已经指出的规则之前。我已经给出了一些低级的细节,但是对于java,最好使用这个高级模型,而不是从硬件的Angular 来考虑。仅从硬件/围栏的Angular 考虑,这只适用于Maven,不可携带且非常脆弱。
b
a=1
b=1
a
1条答案
按热度按时间jutyujz01#
volatile可防止两种不同的问题:
能见度
重新排序
我假设x86。。
首先,x86上的缓存总是一致的。因此,在一个cpu将某个变量的存储提交到缓存之后,另一个cpu仍然会加载该变量的旧值,这是不可能的。这是mesi协议的域。
假设java字节码中的每一个put和get都被翻译(而不是优化)到一个存储和cpu上的一个负载,那么即使没有volatile,每一个get都会看到同一个地址上最近的put。
这里的问题是编译器(在本例中是jit)在优化代码方面有很大的自由度。例如,如果它检测到在循环中读取了相同的字段,它可以决定将该变量从循环中提升出来,如下所示。
吊装后:
如果该字段仅被1个线程触及,则这是很好的。但是如果字段被另一个线程更新,第一个线程将永远看不到更改。使用volatile可以防止此类可见性问题,这实际上是:
c型挥发性
jsr-133引入java内存模型之前的java volatile。
具有不透明访问模式的varhandle。
还有另一个非常重要的方面就是易变性;volatile防止对某些cpu执行的指令流中不同地址的加载和存储进行重新排序。jit编译器和cpu有很大的自由来重新排序加载和存储。尽管在x86上,由于存储缓冲区的原因,只有较旧的存储可以用较新的加载重新排序到不同的地址。
想象一下下面的代码:
事实上
b
是挥发性的防止储存a=1
在商店后面跳b=1
. 它还可以防止a
在…之前跳进去b
. 这样线程2就可以看到a=1
,当它读到b=1
.因此,使用volatile,可以确保非volatile字段对其他线程可见。
如果您想了解volatile是如何工作的,我建议您深入研究java内存模型,它是用synchronize with表示的,发生在margeret bloom已经指出的规则之前。我已经给出了一些低级的细节,但是对于java,最好使用这个高级模型,而不是从硬件的Angular 来考虑。仅从硬件/围栏的Angular 考虑,这只适用于Maven,不可携带且非常脆弱。