SwingWorker:在取消工作线程后调用done()时抛出错误

时间:2017-09-06 13:06:27

标签: java multithreading swingworker

取消SwingWorke任务后,我一直看到以下异常。

Exception in thread "AWT-EventQueue-0" java.util.concurrent.CancellationException

搜索网后,我发现below comment from Oracle

  

注意:如果在其背景之后在SwingWorker对象上调用get   任务已被取消,java.util.concurrent.CancellationException是   抛出。

这是我生成异常的代码。

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JProgressBar;
import javax.swing.SwingWorker;

public class JasperReportGenerator {

    private JButton cancel;
    private JProgressBar pbar;
    private int count = 0;
    private JFrame dialog;

    public JasperReportGenerator() {
        init();
        //Here we do the background task
        SwingWorker<Boolean, Integer> worker = new SwingWorker<Boolean, Integer>() {
            @Override
            protected Boolean doInBackground() throws Exception {
                for (int i = 0; i < 10; i++) {
                    publish(i * 10);
                    Thread.sleep(1000);
                }
                return true;
            }

            @Override
            protected void done() {
                try {
                    dialog.dispose();
                    JOptionPane.showMessageDialog(null, "Done", get().toString(), JOptionPane.INFORMATION_MESSAGE);
                } catch (InterruptedException ex) {
                    Logger.getLogger(JasperReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(JasperReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
                }
            }

            @Override
            protected void process(List<Integer> list) {
                pbar.setValue(list.get(list.size() - 1));
                pbar.setString(list.get(list.size() - 1) + "%");
            }
        };
        worker.execute();

        //cancel the process
        cancel.addActionListener((ActionEvent e) -> {
            worker.cancel(true);
            dialog.dispose();
            System.out.println("bg task cancelled...");
        });

    }

    private void init() {
        dialog = new JFrame("Progress Report");
        dialog.setLocationRelativeTo(null);
        cancel = new JButton("Cancel");
        pbar = new JProgressBar(0, 100);
        pbar.setStringPainted(true);
        pbar.setIndeterminate(false);
        dialog.setPreferredSize(new Dimension(400, 250));
        dialog.setLayout(new FlowLayout());
        dialog.getContentPane().add(pbar);
        dialog.getContentPane().add(cancel);
        dialog.pack();
        dialog.setVisible(true);
    }

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(() -> {
            new JasperReportGenerator();
        });
    }

}

我搜索了一个我看到thisthis的解决方案,但在我的情况下我无法fit

这是我用done()方法解决问题的方法

  @Override
        protected void done() {
            try {
                if (!isCancelled()) {
                    JOptionPane.showMessageDialog(null, "Done", get().toString(), JOptionPane.INFORMATION_MESSAGE);
                    dialog.dispose();
                }

            } catch (InterruptedException ex) {
                Logger.getLogger(JasperReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
            } catch (ExecutionException ex) {
                Logger.getLogger(JasperReportGenerator.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

使用上面设计的done(),异常不会抛出。

现在我想知道这是否是nice解决方案?这段代码的含义是什么?

1 个答案:

答案 0 :(得分:1)

您的解决方案不完善,因为在您调用isCancelled()和调用get()之间可能会发生取消,这很少会导致异常。最好是捕获CancellationException并处理它。