Java中while(true)循环未检测条件成立,加else才生效的问题
问题
在Main类中定义了两个初始值为false的public static布尔变量:
public class Main { public static boolean isToggled = false; public static boolean isClicking = false; public static void main(String[] args){ while(true){ if(Main.isToggled && Main.isClicking){ System.out.println("Running"); } } } }
期望通过while(true)循环持续检测这两个变量是否被其他线程设为true,但当两个变量均被设为true时,循环无任何输出。
仅当为循环添加else语句后,循环才能正常检测到条件成立并执行对应逻辑:
public class Main { public static boolean isToggled = false; public static boolean isClicking = false; public static void main(String[] args){ while(true){ if(Main.isToggled && Main.isClicking){ System.out.println("Running"); } else{ System.out.println("Idle"); } } } }
已验证设置变量值的线程功能正常,移除while循环后可正常输出变量修改后的值。以下是可复现问题的测试代码:
public class Main { public static boolean isToggled = false; public static boolean isClicking = false; public static void main(String[] args) { Thread changeBoolsT = new Thread(new Runnable() { @Override public void run() { changeBools(); } }); changeBoolsT.start(); while(true){ if(isToggled && isClicking){ System.out.println("OK"); break; } else{ // Remove this else statement System.out.println("Waiting"); } } } public static void changeBools(){ try{ Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } isToggled = true; isClicking = true; } }
请求解释为何无else语句时while(true)循环无法检测到条件成立,添加else语句后却能正常工作。
原因解释
核心问题出在JIT即时编译器的优化和Java内存可见性规则上:
- 无else语句时,main线程的while循环是一个空忙循环,JIT编译器会分析代码逻辑,发现
isToggled和isClicking在当前线程(main线程)里没有被修改操作,于是会做激进优化——把这两个变量的值缓存到CPU寄存器中,后续循环不再从主内存读取最新值。哪怕其他线程已经把这两个变量改成true,main线程读取的始终是寄存器里的旧值,自然无法触发条件判断。 - 添加else语句后,里面的
System.out.println("Idle")调用了PrintStream.println方法,这个方法内部是加了同步锁的。根据Java内存模型,同步操作(锁的获取/释放)会强制线程刷新主内存,读取变量的最新值;同时JIT编译器不会对包含同步操作的循环做缓存优化,所以main线程能及时读到其他线程修改后的变量值,条件判断就能正常触发。
解决方法
如果不想依赖同步操作来保证可见性,可以直接把变量声明为volatile,它会禁止JIT对变量做缓存优化,强制线程每次都从主内存读取最新值:
public static volatile boolean isToggled = false; public static volatile boolean isClicking = false;
内容的提问来源于stack exchange,提问作者henri
相关产品推荐
相关产品推荐

