java - 从 SwingWorker 调用 done 方法时是否必须使用 Runnable.run
问题描述
作为学习 SwingWorker 的一部分,我正在浏览源代码,并在其中找到了以下代码。我有一个关于这个的问题。
private void doneEDT() {
Runnable doDone =
new Runnable() {
public void run() {
done();
}
};
if (SwingUtilities.isEventDispatchThread()) {
doDone.run();
} else {
doSubmit.add(doDone);
}
}
上面的 doneEDT 是从 SwingWorker 构造函数调用的,如下所示,
public SwingWorker() {
Callable<T> callable =
new Callable<T>() {
public T call() throws Exception {
setState(StateValue.STARTED);
return doInBackground();
}
};
future = new FutureTask<T>(callable) {
@Override
protected void done() {
doneEDT();
setState(StateValue.DONE);
}
};
state = StateValue.PENDING;
propertyChangeSupport = new SwingWorkerPropertyChangeSupport(this);
doProcess = null;
doNotifyProgressChange = null;
}
问题
为什么该done()
方法包含Runnable
在 doneEDT 方法中?done()
可以直接调用该方法,而无需将其包装在Runnable
right?中。所以我在想将它包装在一个Runnable
?
所以这个问题出现在我的脑海里。
解决方案
你把两种不同的done()
方法混为一谈。一个是SwingWorker
你打算覆盖的。Runnable
在您的实现中不需要发生什么特别的事情done()
,只有您自己的代码。(一个健壮的实现done()
将检查,如果您没有在其他地方调用它isCancelled
,可能get()
会调用它并处理可能由工作人员抛出的任何异常等。但您不需要包装 aRunnable
来执行任何操作。)
另一种方法是FutureTask
's。这会让人感到困惑,因为 SwingWorker 本身使用 FutureTask 来完成处理并发的“真正”工作。FutureTask#done()
也意味着被客户端覆盖,但在这种情况下,客户端是 SwingWorker,而不是你。
当您调用 execute() 时,SwingWorker future
(FutureTask 的私有实例变量)开始运行,会发生以下情况:
future.run()
在工作线程中运行。future.run()
调用上面引用的 Callable ,将状态更改为 STARTED (发送属性事件)并调用doInBackground
. 您自己的工作代码运行并返回结果。future.run()
调用它自己的“set”方法来存储结果并将计算标记为完成。它还调用私有方法finishCompletion
。future.finishCompletion()
唤醒任何其他调用 SwingWorker 的线程get()
(因此一直被阻塞)。这些调用get()
可以在此列表的其余部分发生的同时将计算结果返回给它们的调用者。future.finishCompletion()
调用它自己的done()
. 通常这是一个空方法,但正如您在上面引用的那样,SwingWorker 进行了覆盖。所以这个特定的FutureTaskdone()
做了两件事:首先,它调用SwingWorker#doneEDT()
,它只是调用SwingWorker#done()
事件调度线程。这是done()
您在 SwingWorker 的子类中覆盖的版本。其次,它将状态更改为 DONE,这会发送另一个属性更改事件。future
'finishCompletion()
返回到它的 'set' 方法,该方法返回到run()
,它会做一些家务,然后返回。那时,工作线程被释放用于其他事情(新工作、睡眠、爱好等)。
done()
如果你想继承它,你自己的参与只会与 SwingWorker's 相关联。多亏了 SwingWorker 的杂耍,你自己的重写done()
保证在事件调度线程上运行,所以你可以安全地使用 Swing 可视化组件做事。请注意,done()
如果 SwingWorker 被取消,也会被调用,即使cancel()
之前被调用execute()
——事实上,done()
在cancel()
返回之前被调用——所以在你的覆盖中相应地检查状态。
推荐阅读
- python - 如何将多进程更改为单进程
- python - 仅使用从长到宽的列来旋转数据框
- json - jq 获取对象列表中给定键的所有唯一值
- android - 如何用密码字符填充editText,所以那里有隐藏的字符
- java - 使用 webclient 同时进行多个调用:当 webClient 抛出连接异常时,未调用 Flux .doOnTerminate
- rancher - 为什么 K3s 的 Rancher DNS 故障排除提示似乎只适用于 Busybox 1.28?
- excel - ODBC:错误 [HY000] SSL 异常:无法验证吊销的证书链
- odoo - 以内部用户/管理员身份登录时,Odoo 登录名/密码错误
- python - 面板 Echart 中的自定义轴标签
- c# - Quartz.net Scheduler Trigger 4 次,相差几毫秒 部署在 IIS