【发布时间】:2016-09-17 19:39:57
【问题描述】:
我试图更好地理解 JIT 编译器在 volatile 变量值缓存方面如何为 java 工作。 考虑这个问题中提出的例子: Infinite loop problem with while loop and threading:
boolean loaded = false; // not volatile!!!
private boolean loadAsset() {
new Thread(new Runnable() {
@Override
public void run() {
// Do something
loaded = true;
}
}).start();
while (!loaded) {
System.out.println("Not Loaded");
}
System.out.println("Loaded");
return false;
}
由于变量 loaded 未声明为 volatile,JIT 编译器允许“缓存”注册表中的变量。据说这在理论上可能会导致无限循环,因为执行循环的线程可能在某个时间点看不到变量是从另一个线程更新的。
但是“允许”缓存到底是什么意思呢?变量是否有可能被缓存sometimes,这意味着如果我在同一个 JVM 中运行同一段代码(不关闭 JVM)一百万次,JIT 编译器可能会在某个时候决定缓存变量并产生无限循环?还是 JIT 编译器是一致的,这意味着它要么决定缓存变量,要么不缓存该变量,并且该决定将在 JVM 的整个生命周期中对这段代码的所有数百万次执行保持不变?
【问题讨论】:
-
据我所知(至少在纯 Java 中),您和 JVM 都没有直接控制缓存。缓存由硬件 (CPU) 控制。根据某些因素,缓存中的变量会被覆盖、失效、更新等……因此,变量可能只在某些时候被缓存。但是通过使用
volatile,您可以指示 JVM(以及 CPU)永远不要使用缓存值,而是使用内存值。我不知道volatile是停用缓存还是只指示每次都从内存中读取值。 -
@Turing85:您的评论完全错误;提问者答对了。 HotSpot 优化器可能会发出将值保存在 CPU 寄存器中的本机代码,而不是从堆中重新读取它们。这与缓存具有相同的效果,事实上,在 x86 上,这是内存可见性问题的主要原因,因为真正的 CPU 缓存在该平台上是一致的。
标签: java concurrency volatile jit