Java 处理SwingWorker.doInBackground引发的异常的正确方法

Java 处理SwingWorker.doInBackground引发的异常的正确方法,java,swing,exception,swingworker,event-dispatch-thread,Java,Swing,Exception,Swingworker,Event Dispatch Thread,处理类的方法引发的异常的正确方法是从方法内部调用该方法,如前所述 该方法的文档说明如下: 如有必要,等待计算完成,然后检索 它的结果 注意:在事件分派线程上调用get,将阻止所有 事件(包括重绘)从正在处理到 SwingWorker已完成 因此,如果get方法在done方法中导致等待,实际上它会阻止事件分派线程,因为done方法是在EDT上执行的 但是,在对建议的解决方案执行简单测试后,您可能会注意到EDT没有被阻止:发生这种行为是因为get方法在done方法中被调用,因此get在计算操作结果后

处理类的方法引发的异常的正确方法是从方法内部调用该方法,如前所述

该方法的文档说明如下:

如有必要,等待计算完成,然后检索 它的结果

注意:在事件分派线程上调用
get
,将阻止所有 事件(包括重绘)从正在处理到
SwingWorker
已完成

因此,如果
get
方法在
done
方法中导致等待,实际上它会阻止事件分派线程,因为
done
方法是在EDT上执行的

但是,在对建议的解决方案执行简单测试后,您可能会注意到EDT没有被阻止:发生这种行为是因为
get
方法在
done
方法中被调用,因此
get
在计算操作结果后被调用,因此,对它的调用不会阻止EDT。这个动机正确吗

因此,如果get方法在done方法中导致等待,实际上它会阻塞事件分派线程,因为done方法是在EDT上执行的

实际上,如果调用了done,则
doInBackground
已经返回,因此在
done
内调用
get
不会阻塞事件调度线程

如果您正在使用
PropertyChangeListener
支持并监视状态更改为
DONE

已更新

因此,在查看后,这意味着对已取消的worker调用
get
将独立地阻止EDT,基本的解决方法实际上是通过检查
SwingWorker#isCancelled
状态来忽略返回结果。让我们面对它,如果工作进程被取消,返回结果是未知的/未定义的,因此最好不要尝试获取它

例如(基于bug中的代码)

import java.util.concurrent.ExecutionException;
导入javax.swing.SwingWorker;
公共班机{
公共静态void main(字符串[]args)引发InterruptedException{
SwingWorker worker=新SwingWorker(){
@凌驾
受保护的字符串doInBackground()引发异常{
试一试{
而(!Thread.currentThread().isInterrupted()){
System.out.println(“工作…”);
睡眠(1000);
}
}捕获(中断异常例外){
System.out.println(“被中断了!”);
}
试一试{
系统输出打印(“清理”);
睡眠(10000);
系统输出打印(“完成清洗”);
}捕获(中断异常例外){
System.out.println(“第二次被中断了!”);
}
返回null;
}
@凌驾
受保护的void done(){
系统输出打印项次(“完成”);
如果(!isCancelled()){
长启动=System.currentTimeMillis();
试一试{
get();
}捕获(InterruptedException | ExecutionException ex){
例如printStackTrace();
}
long end=System.currentTimeMillis();
System.out.println(“take”+((结束-开始)/1000d));
}否则{
系统输出打印项次(“已取消”);
}
}
};
worker.execute();
睡眠(10000);
worker.cancel(true);
睡眠(20000);
}
}

如果使用了
cancel
,则此选项可能不起作用。(bug)@radiodef理论上,如果取消,get“应该”抛出一个InterruptedException。我很想知道这是否只是java 8中的一个bug我不太记得行为的本质,但我认为如果使用了
取消
,则
get
有可能在
done
内阻止
done
。我在Java6上遇到了这个bug,所以它显然已经存在了一段时间。还有一份旧的报告@enzom83是的,我所指的问题,在bug报告链接中提出,如果使用了
cancel(true)
,则在
doInBackground
返回之前可以调用
done
。再想一想,我想在这种情况下,
get
不会阻塞,它会抛出
CancellationException
(就像MadProgrammer必须参考上面提到的那样)。@Radiodef已经测试了bug报告中的代码,简单的“解决方法”是检查
done
方法中
SwingWorker#isCancelled
属性的状态,如果是,则“return”值未知/未定义,不应获取,否则可以检查它。正如错误报告响应中所述,“要取消正在运行的任务,它应该是可取消的,即响应中断”-这将建议工作人员本身(在
doInBackground
方法中)应该在其工作周期内检查
Thread.currentThread().isInterrupted()
isCancelled
状态
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();
    }
}