Java JIT 编译器优化 - JIT 在可变变量值缓存方面是否一致?

Java JIT compiler optimizations - is JIT consistent in respect to volatile variables value caching?

我试图更好地了解 JIT 编译器如何在 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 编译器 allowed "cache" 注册表中的变量.据说这在理论上会导致无限循环,因为执行循环的线程可能在某个时间点看不到变量是从另一个线程更新的。

但是 "allowed" 缓存到底是什么意思?变量是否有可能 有时 被缓存,这意味着如果我 运行 同一 JVM 中的同一段代码(不关闭 JVM)一百万次, JIT 编译器可能会在某个时候决定缓存变量并产生无限循环?或者 JIT 编译器是否一致,这意味着它会决定是否缓存变量,并且该决定会在 JVM 的整个生命周期中对这段代码的所有百万次执行产生影响?

此处的缓存发生在硬件级别,CPU 可能会决定从其缓存中读取变量的值,丢弃其他线程在其自己的缓存中写入的值。

然而,JIT 可能会优化循环并将其变成无限循环,因为循环内未设置布尔标志,这与从缓存中读取陈旧值不是必需的。

"Allowed to cache" 这里可能被解释为,JIT 没有义务在读取变量时发出 fence instruction

回答你的最后一个问题,是的,有可能是 JIT 在程序 运行 一段时间后决定以这种方式优化循环。

JVM 使用启发式方法来决定何时在不同的优化级别编译或重新编译一个方法;有问题的优化可能只发生在特定的优化级别。 JIT 编译器始终存在一定程度的可变性。