为了账号安全,请及时绑定邮箱和手机立即绑定

循环完成后程序未终止

循环完成后程序未终止

守候你守候我 2024-01-17 17:08:40
在以下场景中,布尔值“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 关键字,除非它是绝对必须的,并且我确实明白,通过将我的值暴露给所有线程(这不是我打算公开的)可以工作。
查看完整描述

2 回答

?
HUX布斯

TA贡献1876条经验 获得超6个赞

每个线程都为性能创建了不同的已缓存版本的did,您的计数器线程太忙于进行计数计算以至于没有机会重新加载did

易失性确保任何读/写都在主内存上完成,始终更新 cpu 缓存副本。

Thread.sleep 总是暂停当前线程,因此即使 0 你的计数器线程被中断一段<1ms的时间,这也足以让线程被告知完成变量更改。


查看完整回答
反对 回复 2024-01-17
?
四季花海

TA贡献1811条经验 获得超5个赞

我不是 Java 专家,我什至不会用 Java 编程,但让我尝试一下。

Java 语言规范第 17 章定义了内存操作(例如共享变量的读写)的happens-before关系。仅当写入操作发生在读取操作之前时,才保证一个线程的写入结果对另一线程的读取可见。同步和易失性构造以及Thread.start()和Thread.join()方法可以形成happens-before关系。

如果您浏览该线程,它会提到执行共享变量的线程时的“发生在”逻辑。所以我的猜测是,当您调用 Thread.sleep(0) 时,线程能够正确设置 did 变量,确保它“首先发生”。但是,在多线程环境中,甚至不能保证这一点。但由于代码片段非常小,因此在这种情况下仍然可以工作。

总而言之,我只是运行了您的程序,并对变量“done”进行了微小的更改,并且该程序按预期工作:

private static volatile boolean done;

谢谢。也许其他人可以给你更好的解释:P


查看完整回答
反对 回复 2024-01-17
  • 2 回答
  • 0 关注
  • 59 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信