Java多线程中while循环无法感知变量更新的问题
问题原因与解决方案
原循环无法感知变量更新的核心原因
这是Java内存模型(JMM)的可见性问题,叠加JIT即时编译器的激进优化导致的:
- 当线程执行无停顿的无限循环时,JIT编译器会判定循环内没有触发线程状态切换的操作(比如同步、休眠、IO等),于是将
shirt.isColorBlue()的结果缓存到当前线程的工作内存中,不再每次去主存读取最新的shirt颜色值。 - 其他线程更新shirt颜色时,是把新值写入主存,但循环线程一直使用工作内存里的旧缓存值,自然永远触发不了if块。
为什么加Thread.sleep(1000)就正常了?
Thread.sleep()会让当前线程放弃CPU、进入休眠状态,直接打破了JIT的优化逻辑:
- 线程休眠唤醒后,会重新从主存读取变量的最新值,而非继续使用缓存的旧值。
- JIT不会对包含sleep的无限循环做“缓存变量”的激进优化,因为它能预判到线程休眠期间,其他线程可能修改了变量。
正确的解决方式(替代sleep)
sleep只是碰巧规避了问题,并非正规的多线程同步方案,推荐两种标准做法:
- 用volatile修饰color属性:给shirt的color变量加上
volatile关键字,强制所有线程读取该变量时必须从主存获取最新值,写入时立刻同步到主存,从根源保证可见性。// shirt类中的color定义示例 private volatile String color; - 使用同步块/方法:用
synchronized包裹读取或修改color的代码块,同步操作会自动保证主存与工作内存的变量同步。// 读取时加同步锁 while(true){ synchronized(shirt) { if (shirt.isColorBlue()) { System.out.println("The shirt is finally blue."); } } } // 修改color的线程也需用同一锁同步 synchronized(shirt) { shirt.setColor("blue"); }
内容的提问来源于stack exchange,提问作者codertryer
相关产品推荐
相关产品推荐

