
swingworker 的 doinbackground 方法可能因未捕获异常而提前终止,若不在 done() 中调用 get(),异常将被静默吞没,导致循环中断、进度停滞等看似“只执行一次”的假象。
在 Swing 应用中,SwingWorker 是执行耗时任务并安全更新 UI 的核心工具。然而,如示例所示,当 doInBackground() 中的循环(例如遍历 2000 个 ticker)意外只执行一次便触发 done(),往往并非逻辑错误,而是后台异常被忽略所致。
根本原因在于:SwingWorker 在 doInBackground() 中抛出任何未捕获的异常(如 NullPointerException、IndexOutOfBoundsException 或远程调用失败引发的 RuntimeException)时,会立即终止执行,并将异常封装为 ExecutionException —— 但该异常不会自动打印或中断主线程,除非显式调用 get()。若 done() 方法中未调用 get(),异常将彻底丢失,SwingWorker 状态变为 DONE,process() 和 done() 照常执行,造成“任务似乎完成但数据不全”的错觉。
✅ 正确做法是在 done() 中调用 get(),并妥善处理可能的异常:
protected void done() {
try {
get(); // 关键:强制获取结果或抛出原始异常
System.out.println("任务成功完成");
// 可在此刷新 UI、启用按钮等
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.err.println("任务被中断");
} catch (ExecutionException e) {
Throwable cause = e.getCause();
System.err.println("后台任务异常:" + cause.getClass().getSimpleName());
cause.printStackTrace(); // 打印真实异常堆栈(如 NPE、IOException)
// 可选:弹出错误提示、记录日志、重置进度条等
}
}⚠️ 注意事项:
- get() 是阻塞调用,但 done() 已在 Event Dispatch Thread(EDT)中执行,且此时 SwingWorker 已结束,因此调用 get() 是安全的(不会卡住 UI);
- 不要省略 InterruptedException 处理:需恢复线程中断状态;
- 示例中 markets.add(...) 若 rc.getAll24HrPriceStatistics() 返回 null,或 tickers.get(i) 返回 null 后调用 .getSymbol(),极易触发 NullPointerException —— 这正是循环中断的典型诱因;
- 建议在 doInBackground() 开头添加防御性检查:
if (tickers == null) { throw new IllegalStateException("Ticker 列表为空,服务调用可能失败"); }
总结:SwingWorker 的健壮性依赖于显式异常感知。始终在 done() 中调用 get(),不仅是为了“获取返回值”,更是为了主动捕获和响应后台异常。这是避免“任务静默失败”、提升 Swing 应用可维护性的关键实践。










