Java 带while循环和线程的无限循环问题
用一个基本的例子来说明我的问题,我有两个几乎相同的代码位 此代码导致Java 带while循环和线程的无限循环问题,java,multithreading,while-loop,infinite-loop,Java,Multithreading,While Loop,Infinite Loop,用一个基本的例子来说明我的问题,我有两个几乎相同的代码位 此代码导致while循环无限运行 private boolean loadAsset() { new Thread(new Runnable() { @Override public void run() { // Do something loaded = true; } }).start(); while (
while
循环无限运行
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;
}
但是,此代码(即在while循环中执行某些操作)会导致成功计算加载的变量,并允许while
循环中断,方法完成
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
,因为其值仅由单个线程写入。检查“loaded”是否明确声明为volatile
说明:如果变量由多个线程读取和/或写入,则需要采取适当的线程安全措施。一个这样的线程安全度量是volatile,它适用于原语值(或对象引用),原语值作为“简单”操作读取或写入,并且在给定情况下写入的值不取决于先前读取的值。关于更多信息,我在我的网站上有一篇关于线程安全的文章(以及其他关于线程安全的一般信息),可能会有所帮助。第一个循环只“出现”无限运行。实际上,您正在运行一个“活动等待”,消耗100%的CPU,这样您的操作系统或JVM就无法进行上下文切换而让另一个线程运行
另一方面,使用System.out.println()
时,会涉及I/O,导致某种程度上的“非活动等待”。操作系统或JVM可以切换上下文,其他线程启动
如果第一个程序运行10个小时,我确信循环最终会中断。如果加载的不是易失性的,JIT可以通过将其放入寄存器而不是每次从内存加载来优化它。在第二种情况下,循环太复杂,JIT无法假设它不需要每次加载loaded
注意:它是JIT而不是优化代码的javac
编译器。我相信您正在经历一个空循环,它永远不会休眠。因此,要将loaded设置为true的线程永远不会运行 为什么您依赖一个可以被其他字段更改的字段值?您可能需要在块同步的情况下使整个块保持良好状态。我没有意识到…@Peter Lawrey,缓存是由CPU控制的而不是JIT,我认为加载的可能会在缓存已满时被丢弃,然后再次从内存加载。请参阅。事实上,JIT将while循环优化为无限循环,请参阅。对,但没有解释?嗯……哦,好吧对不起,我添加了一个解释。