调用wait()方法后JFrame显示空白、应用程序冻结问题求助
问题根源
- 第一,你阻塞了Swing的事件调度线程(EDT):Swing采用单线程渲染模型,所有UI重绘、用户输入事件回调(包括你写的
dispatchKeyEvent)都必须在EDT上执行。如果你是在EDT中调用了sharedObject.wait(),会直接挂起EDT,既无法触发JFrame重绘导致界面变白,也无法执行键盘输入的回调逻辑,notify永远不会被触发,程序直接死锁。 - 第二,锁对象不匹配:你等待的对象是
sharedObject,但键盘逻辑中调用notify的是lockObject,两个是完全独立的对象,就算EDT没有被阻塞,notify也无法唤醒等待中的线程。
修复方案
步骤1:拆分游戏逻辑线程和UI线程
把游戏主逻辑、等待输入的逻辑放到单独的子线程中运行,绝对不要在EDT中执行任何阻塞操作。所有需要修改UI的操作,再通过SwingUtilities.invokeLater()抛回EDT执行,示例代码如下:
// 游戏初始化时启动独立的逻辑线程 new Thread(() -> { boolean gameRunning = true; while (gameRunning) { // 等待玩家输入 try { synchronized (lockObject) { lockObject.wait(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } // 处理玩家输入逻辑(角色移动、数值计算等非UI操作) processPlayerMove(playerInput); // 涉及UI更新的操作必须抛回EDT执行 SwingUtilities.invokeLater(() -> { // 在这里执行更新角色位置、刷新界面、重绘地图等UI操作 updateGameUI(); }); } }).start();
步骤2:统一锁对象
保证等待逻辑和通知逻辑使用同一个锁对象,把你原有的等待代码里的sharedObject替换成和键盘逻辑一致的lockObject即可。
可选优化
你可以用CountDownLatch、CompletableFuture这类JUC工具代替原始的wait/notify,代码可读性更高,也更不容易出现锁匹配错误的问题。
内容的提问来源于stack exchange,提问作者bobk12l
相关产品推荐
相关产品推荐

