2010-03-01 2 views
6

Я пытаюсь реализовать класс SwingWorker в своем приложении. Есть ли способ установить промежуток времени, после которого SwingWorker «истекает»? Я думал, что, возможно, выбрасывает исключение OutOfTime, которое я могу поймать, а потом разобраться. Я просто не знаю, как его реализовать.Тайм-аут задачи с Java SwingWorker

Спасибо за вашу помощь!

ответ

4

Почему бы не встроить свою задачу в пределах Runnable, поместите его в новый однопоточных ExecutorService, а затем выполнить get() на результирующее Future с соответствующим тайм-аут. Это даст вам возможность таймаута, так как get() будет генерировать исключение, если задание не будет завершено вовремя.

+0

Также: просто вызов get() с тайм-аутом по-прежнему будет оставлять (предположительно дорогостоящую) работу, которую нужно выполнить позже. Задача также должна быть отменена (и написана таким образом, что ее отмена действительно работает) – Sbodd

+0

Вы можете прервать() свою работу с помощью метода Future.cancel() –

+0

(который, как мне кажется, генерирует исключение ThreadInterruptedException) –

1

Короткий ответ: «Это сложно», в зависимости от ваших требований. Я настоятельно рекомендую прочитать Java Concurrency In Practice.

Основная вещь, которую вы могли бы сделать, заключалась бы в том, чтобы (a) убедиться, что Runnable SwingWorker является дружественным к прерываниям и (b) установить таймер (или использовать вызов блокировки get(), обозначенный Брайаном), чтобы отменить ваше Будущее.

1

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); 
} 

}

+0

Выполнение выполненных действий () всегда будет ловить 'java.util.concurrent.TimeoutException' там. Это намеренно? – DejanLekic

Смежные вопросы