java - while循环应用了什么样的优化JIT

标签 java performance jvm jit

我写下了这段代码:

public class Main {

    private boolean stopThread = false;
    private int counter = 0;

    public static void main(String[] args) throws InterruptedException {
        final Main main = new Main();

        new Thread(() -> {
            try {
                System.out.println("Start");
                Thread.sleep(100);
                System.out.println("Done");
                main.stopThread = true;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }).start();

        new Thread(() -> {
            while (!main.stopThread) {
                main.counter++;
            }
            System.out.println(main.counter);
        }).start();
        System.out.println("End");
    }
}

当我运行它时,while循环将永远运行。我在这个问题上遇到了一些困难,并且我很困惑该代码应用了哪种优化 JIT。

首先,我认为这是 stopThread 变量的可见性问题,但即使它是 true,while 循环也应该晚于我将 stopThread 指定为 true (当第一个线程的 CPU 缓存刷新到主内存时),所以情况不可能如此。它看起来像 JIT 硬编码 falsestopThread 变量,如果是 true,为什么这个变量在运行时不会以某种方式定期刷新?

显然, volatile 关键字解决了这个问题,但它并没有回答我这个问题,因为 volatile 可以确保可见性并防止 JIT 进行多次优化。

更重要的是,当我将 sleep 时间更改为 1 毫秒时,第二个线程将正确终止,因此我非常确定这与变量可见性无关。

更新:值得一提的是,当 sleep 时间设置为时,我从计数器获得非零值1-10 毫秒。

更新2:另外,我可以说-XX:+PrintCompilation显示,如果 sleep 时间设置为100 ms while 循环被编译,并且发生了堆栈替换

更新3:可能这就是我正在寻找的:https://www.youtube.com/watch?v=ADxUsCkWdbE&feature=youtu.be&t=889 。正如我所想 - 这是 JIT 执行的“优化”之一,防止这种情况的方法是将变量指定为 volatile,或者将 loadloadFence 作为第一行在 while 循环中。

答案:正如@a​​pangin所说:

This optimization is Loop invariant hoisting. JIT is allowed to move the load of stopThread out of the loop, since it may assume that non-volatile field does not change externally, and JIT also sees that stopThread does not change inside the loop.

最佳答案

原因不是 JIT 优化。您的代码正在对共享变量 stopThread (我们称之为“标志”)进行非同步访问。

本质上,在将标志设置为真值的线程与检查该值的另一​​个线程之间存在竞争条件。如果在进入循环之前该标志设置为 true,则代码完成。如果不是(竞争失败),循环将无限期地持续下去,因为 CPU 缓存保存的是 false 值。当标志为 volatile 时,其值是从主内存而不是CPU缓存中读取的,并且循环最终在标志设置线程完成 hibernate 后立即完成。

关于java - while循环应用了什么样的优化JIT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59440249/

相关文章:

java - 无参数构造函数的目的是什么?

java - Firebase 数据库未正确同步

java - Android SQLite,如何将Cursor变成字符串?

java - 跨 JVM 或应用程序实例或 Tomcat 实例的单例

java - 如何设置HSQLDB的时区?

performance - 为什么Docker在Raspberry上将我的容器的CPU使用率限制为100%

performance - 如何测量 Excel 计算时间

functional-programming - 具有按契约(Contract)设计功能的功能语言

java - Linux 上的多个 Java webapps 总线程限制

ios - swift 与 Objective-C : App performance