【问题标题】:Timeout a task with Java's SwingWorker使用 Java 的 SwingWorker 使任务超时
【发布时间】:2010-03-01 15:04:01
【问题描述】:

我正在尝试在我的应用程序中实现 SwingWorker 类。有没有办法设置SwingWorker“超时”的时间长度?我在想可能会抛出一个我可以捕获然后处理的OutOfTime 异常。我只是不确定如何实现它。

感谢您的帮助!

【问题讨论】:

    标签: java swing timeout swingworker


    【解决方案1】:

    为什么不将您的任务嵌入到 Runnable 中,将其放入新的单线程 ExecutorService,然后对生成的 Future 执行 get(),并设置适当的超时时间。这将为您提供超时功能,因为如果作业未及时完成,get() 将引发异常。

    【讨论】:

    • 另外:只是在超时的情况下调用 get() 仍然会让(可能很昂贵的)工作在以后完成。该任务也需要被取消(并以取消它的方式编写)
    • 是的——主要是为了确保提问者知道。 (而 Future.cancel() 只是设置 thread.interrupted() 标志 - 然后您必须实际编写代码来检查它。一些但不是所有 Java 定义的阻塞方法都是可中断的。)
    【解决方案2】:

    简短的回答是“这很难”,具体取决于您的要求。我强烈推荐阅读Java Concurrency In Practice

    您可以做的基本事情是 (a) 确保 SwingWorker 的 Runnable 对中断友好,并且 (b) 设置一个 Timer(或使用 Brian 提到的阻塞 get() 调用)来取消您的 Future。

    【讨论】:

      【解决方案3】:

      内部类 MySwingWorker 可以满足您的需要:

      package com.misc;
      
      import java.awt.event.ActionEvent;
      import java.awt.event.ActionListener;
      import java.util.concurrent.Callable;
      import java.util.concurrent.FutureTask;
      import java.util.concurrent.TimeUnit;
      
      import javax.swing.JButton;
      import javax.swing.JFrame;
      import javax.swing.JPanel;
      import javax.swing.SwingUtilities;
      
      public class FutureStuffGUI extends JFrame {
      /**
       * Provides a variant of SwingWorker which operates with a timeout.
       * 
       * @param <T>
       */
      private static abstract class MySwingWorker<T> {
      
          private T result;
          private Exception raised;
      
          /**
           * Constructor.
           * 
           * @param timeout
           * @param timeUnit
           */
          public MySwingWorker(final long timeout, final TimeUnit timeUnit) {
              result = null;
              raised = null;
      
              System.out.println(Thread.currentThread().getName() + " starting");
              final FutureTask<T> future = new FutureTask<T>(new Callable<T>() {
                  public T call() throws Exception {
                      System.out.println(Thread.currentThread().getName() + " running");
                      T result = doInBackground();
                      return result;
                  }
              });
              System.out.println(Thread.currentThread().getName() + " future: " + future);
              final Thread runner = new Thread(null, future, "FutureThread");
              Thread watcher = new Thread(null, new Runnable() {
      
                  @Override
                  public void run() {
                      runner.start();
                      try {
                          result = future.get(timeout, timeUnit);
                      } catch (Exception ex) {
                          raised = ex;
                      }
                      SwingUtilities.invokeLater(new Runnable() {
      
                          @Override
                          public void run() {
                              assert SwingUtilities.isEventDispatchThread();
                              done();
                          }
                      });
                  }
              }, "WatcherThread");
              watcher.start();
          }
      
          /**
           * Implement this method as the long-running background task.
           * 
           * @return
           * @throws Exception
           */
          abstract protected T doInBackground() throws Exception;
      
          /**
           * This method is invoked from the UI Event Dispatch Thread on completion or timeout.
           */
          abstract protected void done();
      
          /**
           * This method should be invoked by the implementation of done() to retrieve
           * the result.
           * 
           * @return
           * @throws Exception
           */
          protected T get() throws Exception {
              assert SwingUtilities.isEventDispatchThread();
              if (raised != null) {
                  throw raised;
              } else {
                  return result;
              }
          }
      }
      
      public FutureStuffGUI() {
          super("Hello");
          init_components();
      }
      
      private void init_components() {
          JPanel panel = new JPanel();
          JButton button = new JButton("Press");
          panel.add(button);
          add(panel);
          pack();
      
          button.addActionListener(new ActionListener() {
      
              @Override
              public void actionPerformed(ActionEvent e) {
                  new MySwingWorker<String>(5, TimeUnit.SECONDS) {
      
                      @Override
                      protected String doInBackground() throws InterruptedException {
                          assert !SwingUtilities.isEventDispatchThread();
                          System.out.println(Thread.currentThread().getName() + " doInBackground");
      //                        if (true) { throw new RuntimeException("Blow up"); }
                          Thread.sleep(6 * 1000);
                          return "Hello world!";
                      }
      
                      @Override
                      protected void done() {
                          assert SwingUtilities.isEventDispatchThread();
                          String result;
                          try {
                              result = get();
                              System.out.println(Thread.currentThread().getName() + " done; result: " + result);
                          } catch (Exception ex) {
                              System.out.println(Thread.currentThread().getName() + " done; errored:");
                              ex.printStackTrace();
                          }
                      }
                  };
              };
          });
      }
      
      public static void main(String[] args) {
          FutureStuffGUI ui = new FutureStuffGUI();
          ui.setVisible(true);
      }
      

      }

      【讨论】:

      • done() 的实现将始终捕获java.util.concurrent.TimeoutException 那里。这是故意的吗?
      【解决方案4】:

      不使用 SwingWorker.get(long, java.util.concurrent.TimeUnit) 的任何特殊原因?它会抛出 TimeoutException,您可以在应用程序中轻松处理。

      【讨论】:

        猜你喜欢
        • 2021-01-06
        • 1970-01-01
        • 1970-01-01
        • 2013-12-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-09-07
        相关资源
        最近更新 更多