在以下场景中,布尔值“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的时间,这也足以让线程被告知已完成变量更改。
四季花海
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
添加回答
举报
0/150
提交
取消