java - 使用 isCancelled() 时 SwingWorker 不会停止

标签 java multithreading user-interface swingworker

我创建了一个有 3 个按钮的 GUI;连接、断开、中止。它们都共享一个公共(public) 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");
   }
}

最佳答案

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

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

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

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

SwingWorker 生命周期

  • PENDING:从对象构造到调用 doInBackground 之前期间的状态。
  • STARTED:从调用 doInBackground() 之前不久到调用 done() 之前不久期间的状态。 SwingWorker 在进入此状态之前会被分配一个工作线程,并且该工作线程执行 doInBackground()。
    • 在此状态下执行 doInBackground() 时,worker 可以使用 publish(..) 发送中间结果,然后获取 process(.. ) 由事件调度线程 (EDT) 实现。
  • DONE:在事件调度线程 (EDT) 中的 done() 完成执行后,会转换到此状态。这是对象剩余存在的最终状态。

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

根据上述讨论,您可能希望替换 if(this.isDone()) { break; } 包含反射(reflect)您预期处理完成情况的内容。

这里的另一个问题是,您正在由 doInBackground() 调用的方法中执行与 swing 相关的 Activity 。 textArea.append(line + "\n"); 应该发生在事件调度线程中执行的 process(..) 方法中,如下所示:

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

关于java - 使用 isCancelled() 时 SwingWorker 不会停止,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25345105/

相关文章:

Java ExecutorService顺序-Spring MVC

multithreading - 误解单线程和多线程编程之间的区别

c# - 列表的每个枚举都是线程安全的

java - 如何更改新 Material 主题中后退箭头的颜色?

wpf - 使用 WPF 内嵌文本框标签

user-interface - 你最喜欢的用户界面是什么? (Web应用程序)

java - JAXB 嵌套集合

java - 在 IntelliJ IDEA 中使用 Python 脚本作为外部工具

java - 从数据库获取对象时,java.lang.String类型的值连接无法转换为JSONObject

java - 使用java 8流在2个列表中查找元素匹配