【问题标题】:The proper way to handle exceptions thrown by the SwingWorker.doInBackground处理 SwingWorker.doInBackground 抛出的异常的正确方法
【发布时间】:2015-09-07 20:51:43
【问题描述】:

处理SwingWorker 类的doInBackground 方法引发的异常的正确方法是从done 方法中调用get 方法,如herehere 中所述。

get 方法的文档说明如下:

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

注意:在事件调度线程上调用get会阻塞所有 事件,包括重绘,从被处理到此 SwingWorker 已完成。

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

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

【问题讨论】:

    标签: java swing exception swingworker event-dispatch-thread


    【解决方案1】:

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

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

    如果您使用PropertyChangeListener 支持并监控状态更改为DONE,情况也是如此

    更新

    因此,在查看了SwingWorker calls 'done' before the 'doInBackground' is finished 之后,这意味着在已取消的工作人员上调用get 会直接阻塞 EDT,基本的解决方法实际上是通过检查SwingWorker#isCancelled 状态来忽略返回结果.面对现实吧,如果worker被取消,返回结果未知/未定义,所以最好不要尝试get它。

    作为一个例子(基于错误的代码)

    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);
        }
    }
    

    【讨论】:

    • 如果使用cancel,这可能不成立。 (错误)bugs.openjdk.java.net/browse/JDK-8081474
    • @radiodef 理论上,如果取消,“应该”抛出一个 InterruptedException。我很想知道这是否只是 java 8 中的一个错误
    • 我不太记得这种行为的本质,​​但我认为如果使用 cancelget 可能会阻止 done 内部。我在 Java 6 上遇到了这个错误,所以它显然已经存在了一段时间。还有一份较早的报告。 bugs.java.com/bugdatabase/view_bug.do?bug_id=6826514
    • @enzom83 是的,我在错误报告链接中提出的问题是,如果使用cancel(true),则done 可能会在doInBackground 返回之前被调用。再想一想,我想get在这种情况下不会阻塞,它会抛出CancellationException(就像MadProgrammer一定是上面提到的)。
    • @Radiodef 测试了错误报告中的代码后,简单的“解决方法”是检查done 方法中SwingWorker#isCancelled 属性的状态,如果是,则“ return" 值未知/未定义,不应获取,否则,您可以检查它。如错误报告响应中所述“并且要取消正在运行的任务,它应该是可取消的,即响应中断” - 这表明工人本身(在doInBackground方法中)应该检查工作周期中的Thread.currentThread().isInterrupted()isCancelled 状态
    【解决方案2】:
    @Override
    protected void done()
    {
        try
        {
            if(!super.isCancelled())
            {
                super.get();
            }
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-05-04
      • 2015-04-29
      • 2011-08-25
      • 2021-01-20
      • 2016-04-03
      • 2021-12-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多