You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwingWorker的done()方法释放JDialog时异常行为排查

问题根因

本质是Swing事件调度线程(EDT)的任务执行时序 + 模态JDialog的阻塞特性共同导致的问题,和本地查询速度快直接相关:

  1. SwingWorker的publish()方法不会立刻触发process()执行,只是将参数批量打包后异步提交到EDT的任务队列等待调度,done()方法本身同样是提交到EDT队列执行的任务。
  2. 本地数据库查询仅耗时几毫秒,会出现如下时序冲突:
    • doInBackground先提交publish(true)到EDT队列
    • 数据库查询立刻完成,继续提交publish(false)到EDT队列,随后doInBackground执行结束,done()任务也被提交到EDT队列
    • EDT开始执行队列第一个任务:调用loader.setVisible(true)。模态JDialog的setVisible(true)是阻塞方法,会直接卡住当前EDT线程,直到弹窗被手动关闭,队列里后续的publish(false)、done()任务完全没有执行机会。
  3. 远程数据库查询耗时久的场景下没有问题,是因为publish(true)提交后,EDT有足够的时间先执行完setVisible(true)完成弹窗显示,EDT恢复响应后,后续任务可以正常调度执行。

修复方案

方案1(最稳妥):将弹窗显示逻辑移到SwingWorker启动前执行

不要用publish控制弹窗显示,直接在EDT线程中先显示弹窗再启动后台任务,从根源上避免时序冲突:

// 以下代码运行在EDT中
JDialog loader = new MyDialogLoader();
loader.setVisible(true);

new SwingWorker<Void, Void>() {
    @Override
    protected Void doInBackground() {
        // 数据库执行逻辑
        return null;
    }

    @Override
    protected void done() {
        loader.dispose();
        // UI更新逻辑
    }
}.execute();

方案2:修改process逻辑,仅执行最新的状态

如果要保留用publish控制的逻辑,不要遍历chunks里的所有值执行,只取最后一个最新的状态,避免旧的true状态覆盖后续的false状态:

@Override
protected void process(List<Boolean> chunks) {
    // 只取队列最后一个最新的状态
    Boolean latestState = chunks.get(chunks.size() - 1);
    loader.setVisible(latestState);
}

内容的提问来源于stack exchange,提问作者Salim JB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.12 21:09:01