SwingWorker done 方法使用 get() 抛出取消异常



我遇到了为我的 gui 创建停止/启动按钮的问题,经过大量的谷歌搜索,我意识到我需要多线程。在进一步阅读后,我发现了 swingworker 类,我设法让我的 GUI 响应 STOP 按钮。

现在我的问题是这个

doinbackground(( 方法执行一段代码,该

代码在无限的 while 循环中捕获带有条件 (!isCancel( 的数据包,一旦它被取消(STOP 按钮执行 worker.cancel(((,它就会返回一个数据包的 ArrayList,理论上,我应该能够在 done(( 方法中使用 get(( 获取。 对吧?但是当我尝试这样做时,我得到了一个取消异常,这让我现在发疯了。

任何帮助都将受到高度赞赏!谢谢

edit:obj 是在类外部声明的 ArrayList,用于存储返回值。

这是我的代码由 开始 jbutton 执行

private void jButton5ActionPerformed(java.awt.event.ActionEvent evt) {

    final ArrayList packet_list = new ArrayList();
    obj.clear();
    try {
        worker = new SwingWorker<ArrayList,Integer>(){//initialze swingworker class

            @Override
            protected void done(){
                try {  
                    obj = get();
                }
                catch (InterruptedException ex) {
                    Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
                } catch (ExecutionException ex) {
                    Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            //opens up stuff required to capture the packets    
            NetworkInterface   [] devices = JpcapCaptor.getDeviceList();
            int index = (jComboBox5.getSelectedIndex()-1);
            JpcapCaptor captor =JpcapCaptor.openDevice(devices[4], 65535, false, 20); 
            @Override
            protected ArrayList doInBackground(){  
                while(!isCancelled()){
                    try {
                        Packet packets = captor.getPacket(); //captures packets
                        if (packets != null)  //filters out null packets
                        {
                            //System.out.println(packets);
                            packet_list.add(packets); //adds each packet to ArrayList
                        }
                        Thread.sleep(100);
                    } catch (InterruptedException ex) {
                        return packet_list;
                    }
                }
                return packet_list;
            }

        };
        worker.execute();
    } catch (IOException ex) {
        Logger.getLogger(NewJFrame3.class.getName()).log(Level.SEVERE, null, ex);
    }
}                                 

The stop button simply executes 
worker.cancel(); no errors there. and this is the swingworker declaration
 private SwingWorker<ArrayList,Integer> worker;

cancel不只是设置isCancelled标志供您在闲暇时阅读。那几乎是没用的。如果任务尚未启动,它会阻止任务启动,如果线程已在运行,则可能会主动中断线程。因此,获取CancellationException是取消正在运行的任务的自然结果

为了进一步说明这一点,Javadoc on isCancelled 指出:

如果此任务在正常完成之前被取消,则返回 true。

因此,如果返回 true则您的任务无法正常完成。您不能取消任务并期望它正常继续。

SwingWorker文档说"一个抽象类,用于在后台线程中执行冗长的 GUI 交互任务"。但是,对于 GUI 和应用程序生存期,"冗长"的定义是不同的。对于 GUI 来说,100ms 的任务很长,最好由 SwingWorker 完成。对于SwingWorker来说,10 分钟的任务太长了,因为它的线程池有限,您可能会耗尽。从您的问题描述来看,您确实拥有这一点 - 一个可能运行时间很长的任务。因此,您应该宁愿制作适当的后台线程,也不愿使用SwingWorker

在该线程中,您将有一个 AtomicBoolean 或只是一个可以从 EDT 手动设置的 volatile boolean 标志。然后,线程可以将事件与结果一起发布到 EDT。

法典:

class PacketCaptureWorker implements Runnable {
    private volatile boolean cancelled = false;
    public void cancel() {
        cancelled = true;
    }
    public void run() {
        while (!cancelled) {
            //do work
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                //Use the result of your computation on the EDT
            }
        });
    }
}
new Thread(new PacketCaptureWorker()).start();

我尝试使用易失性布尔值而不是使用 worker.cancel(( 作为 swingworker 线程 while 循环,它工作得很好。(至少在表面上(我也设法创建了一个普通的背景线程,这也像一个魅力:D非常感谢你让我头疼!想知道两者中最好的方法是什么。

接下来,我必须使可变布尔值可用于整个类,因为我必须为线程类创建 2 个单独的实例,一个使用 START,另一个使用 STOP。显然,两个不同的实例不能解决变量的同一实例。这是不好的做法吗?

最新更新