Java使用Timer时未等计时结束就执行重绘的问题求助
根本原因
Java Swing采用单线程渲染模型,所有UI更新、重绘、事件响应逻辑都必须在事件调度线程(EDT) 中执行:
- 你直接在主线程/EDT中调用等待方法,会直接阻塞EDT,所有重绘请求要等整个循环执行完才会批量处理,自然看不到中间帧
- 你直接开子线程执行等待+UI更新,非EDT线程操作UI属于非法操作,轻则更新不生效,重则触发线程安全异常
解决方案
用javax.swing.Timer实现异步等待,它的回调逻辑默认运行在EDT中,既能保证UI更新合法,也不会阻塞渲染线程。你原来的同步for循环要拆成按时间触发的分步执行逻辑,参考实现如下:
// 类成员变量,存储处理状态 private ArrayList<Card> betCards; private int currentIndex; private Timer stepTimer; // 启动卡牌处理流程,替换你原来的循环代码 private void startCardProcess() { betCards = Controller.getInstance().playCard(); currentIndex = 0; // 初始化计时器,单次触发,回调运行在EDT中 stepTimer = new Timer(1000, e -> processNextCard()); stepTimer.setRepeats(false); processNextCard(); } private void processNextCard() { if (currentIndex >= betCards.size()) { stepTimer.stop(); return; } int i = currentIndex; if (i == 0 || i % 2 == 0) { if (i == 0 || i == (betCards.size() - 2)) { playerOne.setPlayedCard(betCards.get(i)); currentIndex++; processNextCard(); } else { signe.setText("="); // 第一次等待1秒,设置背面卡牌 stepTimer.setDelay(1000); stepTimer.addActionListener(evt -> { playerOne.setPlayedCard(new Carte(-1, backCarte)); frame.pack(); // 第二次等待1秒后处理下一张 currentIndex++; stepTimer.setDelay(1000); stepTimer.restart(); }); stepTimer.start(); } } else { if (i < 2 || i == betCards.size() - 1) { playerTwo.setPlayedCard(betCards.get(i)); currentIndex++; processNextCard(); } else { signe.setText("="); playerTwo.setPlayedCard(new Carte(-1, backCarte)); currentIndex++; processNextCard(); } } }
注意事项
- 不要混用
java.util.Timer,它的回调运行在子线程,直接更新UI仍会出现异常 - 所有UI修改逻辑全部放在Timer回调中执行即可,不需要额外手动切换线程
内容的提问来源于stack exchange,提问作者Virgil Nauleau
相关产品推荐
相关产品推荐

