猿问

循环完成后程序未终止

在以下场景中,布尔值“done”被设置为 true,这应该结束程序。相反,即使 while(!done) 不再是有效场景,程序也会继续运行,因此它应该停止。现在,如果我要添加线程睡眠,即使睡眠时间为零,程序也会按预期终止。这是为什么?


public class Sample {


    private static boolean done;


    public static void main(String[] args) throws InterruptedException {

        done = false;

        new Thread(() -> {

            System.out.println("Running...");

            int count = 0;

            while (!done) {

                count++;

                try {

                    Thread.sleep(0); // program only ends if I add this line. 

                } catch (InterruptedException e) {

                    e.printStackTrace();

                }

            }

        }).start();


        Thread.sleep(2000);


        done = true; // this is set to true after 2 seconds so program should end.

        System.out.println("Done!"); // this gets printed after 2 seconds

    }


}

编辑:我想了解为什么上面需要 Thread.sleep(0) 来终止。我不想使用 volatile 关键字,除非它是绝对必须的,并且我确实明白,通过将我的值暴露给所有线程(这不是我打算公开的)可以工作。


守候你守候我
浏览 124回答 2
2回答

HUX布斯

每个线程都为性能创建了不同的已缓存版本的did,您的计数器线程太忙于进行计数计算,以至于没有机会重新加载did。易失性确保任何读/写都在主内存上完成,始终更新 cpu 缓存副本。Thread.sleep 总是暂停当前线程,因此即使 0 你的计数器线程被中断一段<1ms的时间,这也足以让线程被告知已完成变量更改。

四季花海

我不是 Java 专家,我什至不会用 Java 编程,但让我尝试一下。Java 语言规范第 17 章定义了内存操作(例如共享变量的读写)的happens-before关系。仅当写入操作发生在读取操作之前时,才保证一个线程的写入结果对另一线程的读取可见。同步和易失性构造以及Thread.start()和Thread.join()方法可以形成happens-before关系。如果您浏览该线程,它会提到执行共享变量的线程时的“发生在”逻辑。所以我的猜测是,当您调用 Thread.sleep(0) 时,主线程能够正确设置 did 变量,确保它“首先发生”。但是,在多线程环境中,甚至不能保证这一点。但由于代码片段非常小,因此在这种情况下仍然可以工作。总而言之,我只是运行了您的程序,并对变量“done”进行了微小的更改,并且该程序按预期工作:private static volatile boolean done;谢谢。也许其他人可以给你更好的解释:P
随时随地看视频慕课网APP

相关分类

Java
我要回答