处理 SwingWorker.doInBackground 抛出的异常的正确方法
The proper way to handle exceptions thrown by the SwingWorker.doInBackground
处理 doInBackground
method of SwingWorker
class is to invoke the get
method from within the done
method, as explained here and here.
抛出的异常的正确方法
get
方法的文档说明如下:
Waits if necessary for the computation to complete, and then retrieves
its result.
Note: calling get
on the Event Dispatch Thread blocks all
events, including repaints, from being processed until this
SwingWorker
is complete.
因此,如果 get
方法导致 done
方法内的等待,实际上它会阻塞事件调度线程,因为 done
方法是在 EDT 上执行的。
但是,在对建议的解决方案进行简单测试后,您可能会注意到 EDT 未被阻止:出现此行为是因为在 done
方法中调用了 get
方法,因此get
在计算出运算结果后调用,因此调用它不会阻塞 EDT。这个动机正确吗?
Therefore, if the get method causes a waiting within the done method, in fact it would block the Event Dispatch Thread, since the done method is executed on EDT.
实际上,如果调用 done,doInBackground
已经 returned,因此在 done
中调用 get
不会阻塞事件调度线程。
如果您使用 PropertyChangeListener
支持并监视状态更改为 DONE
,情况也是如此
已更新
所以,在查看了 SwingWorker calls 'done' before the 'doInBackground' is finished 之后,这意味着在取消的 worker 上调用 get
会自动阻止 EDT,基本的解决方法实际上是忽略 return 通过检查 SwingWorker#isCancelled
状态得到结果。让我们面对现实吧,如果工人被取消,return 结果是 unknown/undefined,所以最好不要尝试 get
它。
举个例子(基于 bug 的代码)
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
public class Main {
public static void main(String[] args) throws InterruptedException {
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
@Override
protected String doInBackground() throws Exception {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Working...");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
System.out.println("Got interrupted!");
}
try {
System.out.println("Cleaning up");
Thread.sleep(10000);
System.out.println("Done cleaning");
} catch (InterruptedException ex) {
System.out.println("Got interrupted second time!");
}
return null;
}
@Override
protected void done() {
System.out.println("Done");
if (!isCancelled()) {
long start = System.currentTimeMillis();
try {
get();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Took " + ((end - start) / 1000d));
} else {
System.out.println("Was cancelled");
}
}
};
worker.execute();
Thread.sleep(10000);
worker.cancel(true);
Thread.sleep(20000);
}
}
@Override
protected void done()
{
try
{
if(!super.isCancelled())
{
super.get();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
处理 doInBackground
method of SwingWorker
class is to invoke the get
method from within the done
method, as explained here and here.
get
方法的文档说明如下:
Waits if necessary for the computation to complete, and then retrieves its result.
Note: calling
get
on the Event Dispatch Thread blocks all events, including repaints, from being processed until thisSwingWorker
is complete.
因此,如果 get
方法导致 done
方法内的等待,实际上它会阻塞事件调度线程,因为 done
方法是在 EDT 上执行的。
但是,在对建议的解决方案进行简单测试后,您可能会注意到 EDT 未被阻止:出现此行为是因为在 done
方法中调用了 get
方法,因此get
在计算出运算结果后调用,因此调用它不会阻塞 EDT。这个动机正确吗?
Therefore, if the get method causes a waiting within the done method, in fact it would block the Event Dispatch Thread, since the done method is executed on EDT.
实际上,如果调用 done,doInBackground
已经 returned,因此在 done
中调用 get
不会阻塞事件调度线程。
如果您使用 PropertyChangeListener
支持并监视状态更改为 DONE
已更新
所以,在查看了 SwingWorker calls 'done' before the 'doInBackground' is finished 之后,这意味着在取消的 worker 上调用 get
会自动阻止 EDT,基本的解决方法实际上是忽略 return 通过检查 SwingWorker#isCancelled
状态得到结果。让我们面对现实吧,如果工人被取消,return 结果是 unknown/undefined,所以最好不要尝试 get
它。
举个例子(基于 bug 的代码)
import java.util.concurrent.ExecutionException;
import javax.swing.SwingWorker;
public class Main {
public static void main(String[] args) throws InterruptedException {
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
@Override
protected String doInBackground() throws Exception {
try {
while (!Thread.currentThread().isInterrupted()) {
System.out.println("Working...");
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
System.out.println("Got interrupted!");
}
try {
System.out.println("Cleaning up");
Thread.sleep(10000);
System.out.println("Done cleaning");
} catch (InterruptedException ex) {
System.out.println("Got interrupted second time!");
}
return null;
}
@Override
protected void done() {
System.out.println("Done");
if (!isCancelled()) {
long start = System.currentTimeMillis();
try {
get();
} catch (InterruptedException | ExecutionException ex) {
ex.printStackTrace();
}
long end = System.currentTimeMillis();
System.out.println("Took " + ((end - start) / 1000d));
} else {
System.out.println("Was cancelled");
}
}
};
worker.execute();
Thread.sleep(10000);
worker.cancel(true);
Thread.sleep(20000);
}
}
@Override
protected void done()
{
try
{
if(!super.isCancelled())
{
super.get();
}
}
catch(Exception ex)
{
ex.printStackTrace();
}
}