移除System.out.println后while循环失效问题咨询
为什么移除注释和println后while循环会失效?
哈哈,这个坑我踩过!核心原因是JVM的即时编译(JIT)优化在搞鬼,具体涉及两个点:死循环优化和内存可见性。
先搞懂原来的代码为啥能正常运行
你之前的代码里有System.out.println(),这个方法可不简单:
- 它内部是加了同步锁的(PrintStream的println方法会同步操作),属于有副作用的操作——JVM知道这个循环里不是啥都没干,不会随便把它优化掉。
- 同步操作还会触发内存屏障,强制线程从主内存读取
bgmPlaying的最新值,而不是用寄存器里缓存的旧值。所以其他线程修改bgmPlaying时,你的检测循环能立刻看到变化。
移除代码后为啥就失效了?
当你把注释和println删掉,这个while循环就变成了一个几乎空的死循环:
while (!bgmPlaying) { // 啥都没干 }
JVM的JIT编译器会识别这种“无副作用的空循环”,直接把它优化成无限循环——甚至会把bgmPlaying的读取缓存到CPU寄存器里,根本不去主内存更新值。这就导致哪怕其他线程修改了bgmPlaying,你的检测循环也永远看不到,看起来就像循环“失效”了。
解决办法(选一个就行)
1. 给bgmPlaying加volatile修饰符
volatile关键字会禁止JVM缓存变量值,强制每次读取都从主内存获取最新值,同时阻止JVM优化空循环:
private volatile boolean bgmPlaying;
2. 在循环里加一个轻量的有副作用操作
比如加Thread.yield(),告诉JVM可以切换线程,同时避免被优化:
while (!bgmPlaying) { Thread.yield(); // 让线程主动让出CPU,同时触发内存屏障 }
或者加一个空的同步块:
while (!bgmPlaying) { synchronized (this) {} // 同步操作会触发内存屏障 }
3. 用AtomicBoolean代替普通boolean
Java并发包的AtomicBoolean自带内存可见性保证,操作都是原子性的,也能避免优化问题:
private AtomicBoolean bgmPlaying = new AtomicBoolean(false); // 检测循环改成 while (!bgmPlaying.get()) { // 可选加yield,不加也能正常工作 }
内容的提问来源于stack exchange,提问作者Al Nafis
相关产品推荐
相关产品推荐

