Java游戏主循环中MouseListener的pressed状态更新未被空循环识别问题
问题根源
这是典型的Java多线程内存可见性问题:
- Swing的鼠标事件回调运行在专属的事件调度线程(EDT)上,而你的游戏主循环运行在单独的自定义线程中
- 你定义的
pressed、isRunning变量都没有添加volatile修饰,JVM执行即时编译优化时,会让主循环线程把这两个变量的值缓存到自身的工作内存中,不会主动去主内存读取最新值 - 空循环执行速度极快,全程没有任何会触发线程内存同步的操作(比如IO、锁、同步方法调用),所以主循环永远读不到EDT线程修改后的变量值;当你加了打印、重绘逻辑时,这些操作隐含了内存同步逻辑,会强制刷新工作内存的缓存,所以就能读到最新值。
修复方案
给两个跨线程读写的变量添加volatile修饰即可:
- 修改ML类的
pressed变量定义:
private volatile boolean pressed = false;
- 修改Game类的
isRunning变量定义:
public volatile boolean isRunning;
可选优化
你也可以用AtomicBoolean替代普通boolean变量,它本身就实现了线程可见性和原子操作,更适合多线程场景下的状态标记。
内容的提问来源于stack exchange,提问作者Derpoulet
相关产品推荐
相关产品推荐

