【问题标题】:SwingWorker not stopping when using isCancelled() [duplicate]SwingWorker 在使用 isCancelled() 时没有停止 [重复]
【发布时间】:2014-10-10 07:00:43
【问题描述】:

我创建了一个有 3 个按钮的 gui;连接、断开、中止。它们都共享一个共同的 SwingWorker 线程,但由于某种原因,除非我点击中止按钮,否则该线程永远不会结束。

我还没有为断开按钮编写任何代码,但即便如此,它与我的问题无关。但是,为什么线程不完成并打印Done 语句?我的猜测是它陷入了this.isCancelled() 循环,但即使我这样做:

while(!this.isCancelled() || !this.isDone()) { // run loop }

它从不打印Done

线程只有在我点击中止按钮后才结束。我正在使用isCancelled() 循环方法,因为这似乎是取消 SwingWorker 的推荐方法。

我只发布下面的相关代码,因为实际上有数百行。

   private class ButtonListener implements ActionListener {

      private MyWorker worker;

      @Override
      public void actionPerformed(ActionEvent e) {

         if(e.getSource().equals(connectButton)) { 

            worker = new MyWorker(activityTextArea);
            worker.execute();
            activityTextArea.append("Connect Button Pressed"); 
         }

         if(e.getSource().equals(disconnectButton)) { 

            activityTextArea.append("Disconnect Button Pressed"); 
         }

         if(e.getSource().equals(abortButton)) { 

            worker.cancel(true);
            activityTextArea.append("Abort Button Pressed"); 
         }
      }
   }

这是 SwingWorker:

public class MyWorker extends SwingWorker<Void, Void> {

   private JTextArea textArea;

   MyWorker(JTextArea textArea) {
      this.textArea = textArea;
   }

   private void startWorker() {

      ProcessBuilder pb = new ProcessBuilder();
      pb.command("aCmd");

      Process p;

      try {
         p = pb.start();

         BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream()));

         String line;

         while((line = br.readLine()) != null) {
            textArea.append(line + "\n");
         }
         br.close();
      } catch (IOException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
   }

   @Override
   protected Void doInBackground() throws Exception {
      // TODO Auto-generated method stub
      boolean isFirstTime = true;

      while(!this.isCancelled()) {

         if(this.isDone()) { break; }

         Thread.sleep(3000);

         if(isFirstTime) {
            startWorker();
            isFirstTime = false;
         } 
      }

      return null;
   }

   @Override
   protected void done() {
      textArea.append("Done\n");
   }
}

【问题讨论】:

    标签: java multithreading user-interface swingworker


    【解决方案1】:

    这里的问题在于 MyWorker.doInBackground() 方法的实现,isDone() 用于控制循环的执行。这可能不是您希望 doInBackground() 工作的方式。

    要真正了解发生了什么,我们需要考虑 isDone() 的行为和 SwingWorker 的生命周期。

    isDone() 方法在以下情况下返回 true:

    • done() 执行完毕后
    • 工人已被取消
    • 由于某些异常而异常终止。

    SwingWorker 生命周期

    • PENDING:从构建对象到调用 doInBackground 之前的状态。
    • STARTED:从调用doInBackground() 之前不久到调用done() 之前不久的这段时间内的状态。 SwingWorker在进入这个状态之前被分配了一个Worker Thread,这个Worker Thread执行doInBackground()。
      • 在此状态下执行doInBackground() 时,worker 可以使用publish(..) 发送中间结果,然后通过事件调度线程 (EDT) 获取process(..)
    • DONE:在 done() 在事件调度线程 (EDT) 中完成执行后转换到此状态。这是对象存在的剩余部分的最终状态。

    了解上述工作流程对于编写高性能且无故障的 GUI 非常重要。

    根据上述讨论,您可能希望将if(this.isDone()) { break; } 替换为反映您预期处理完成的内容。

    这里的另一个问题是,您在由doInBackground() 调用的方法中执行与挥杆相关的活动。 textArea.append(line + "\n"); 应该发生在一个 process(..) 方法中,该方法在 Event Dispatch Thread 中执行,如下所示:

    public class MyWorker extends SwingWorker<Void, String> {
    
        @Override
        protected void process(List<String> chunks) {
            for (String line : chunks) {
                textArea.append(line + "\n"); // display intermediate results from publish()
            }
        }
    
        private void startWorker() throws IOException {
    
            ProcessBuilder pb = new ProcessBuilder("aCmd");
            BufferedReader br = null;
    
            try {
                Process p = pb.start();
                br = new BufferedReader(new InputStreamReader(p.getInputStream()));
                String line;
                while ((line = br.readLine()) != null) {
                    publish(line); // publish a chunk of result to process(..)
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (br != null) br.close();
            }
        }
    

    参考:http://docs.oracle.com/javase/7/docs/api/javax/swing/SwingWorker.html

    【讨论】:

      猜你喜欢
      • 2012-03-22
      • 1970-01-01
      • 2011-12-26
      • 1970-01-01
      • 1970-01-01
      • 2017-03-13
      • 2021-06-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多