2010-03-01 9 views
6

Sto tentando di implementare una classe SwingWorker all'interno della mia applicazione. C'è un modo per impostare un periodo di tempo che dopo di che, lo SwingWorker "scade"? Stavo pensando che forse lanciando un'eccezione OutOfTime che posso catturare e poi affrontare. Non sono sicuro di come implementarlo.Timeout di un'attività con Java SwingWorker

Grazie per tutto il vostro aiuto!

risposta

4

Perché non incorporare il tuo compito all'interno di un Runnable, cadere in un nuovo thread singolo ExecutorService e quindi eseguire una get() sul risultante Future con un timeout appropriato. Questo ti darebbe la tua funzionalità di timeout, poiché get() genererà un'eccezione se il lavoro non viene completato in tempo.

+0

Inoltre: solo chiamare get() con un timeout lascerebbe comunque il lavoro (presumibilmente costoso) svolto in seguito. L'attività deve anche essere annullata (e scritta in modo tale che l'annullamento funzioni effettivamente) – Sbodd

+0

È possibile interrompere() il proprio lavoro tramite un metodo Future.cancel() –

+0

(che genera un ThreadInterruptedException, penso) –

1

La risposta breve è "è difficile", a seconda di quali sono le vostre esigenze. Consiglio vivamente di leggere Java Concurrency In Practice.

La cosa fondamentale che si potrebbe fare sarebbe quella di (a) assicurarsi Runnable del SwingWorker è interrompere-friendly, e (b) impostare un timer (o utilizzare il get blocco() chiama Brian menzionato) per annullare il vostro futuro.

1

La classe MySwingWorker interno può benissimo fare quello che ti serve:

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

Implementazione di done (prenderà sempre il 'java.util.concurrent.TimeoutException' lì. È intenzionale? – DejanLekic