2009-08-24 12 views
7

Estoy usando java.util.Timer para programar una tarea periódica. En un momento dado, me gustaría cerrarlo y esperar a que termine.Esperando a que termine el temporizador en Java

Timer.cancel() evitará que se ejecuten tareas futuras. ¿Cómo puedo asegurarme de que las tareas no se están ejecutando en este momento (o esperar por ellas si lo están?)

Puedo introducir mecanismos de sincronización externos, pero no veo cómo pueden cubrir todos los casos. Por ejemplo, si sincronizo en algún Monitor dentro de la tarea, aún extraño el caso cuando la tarea recién comenzó a ejecutarse pero no tomó el monitor.

¿Cuál es la práctica recomendada para esperar hasta que se realicen todas las tareas, incluidas las tareas que se están ejecutando actualmente?

Respuesta

18

Sería mejor utilizar un ScheduledExecutorService en lugar de un temporizador para programar su tarea periódica. ScheduledExecutorService proporciona un método shutdown() que ejecutará las tareas pendientes. A continuación, puede llamar a awaitTermination() para esperar a que termine shutdown().

+0

+1. O, si tiene que usar un 'Timer' por algún motivo, puede usar una condición (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ Condition.html) para sincronizar dos hilos en un evento (como la finalización de la tarea programada). –

+2

Sí, el elemento 68 en Effective Java (2nd ed) recomienda ScheduledThreadPoolExecutor como un reemplazo más flexible para Timer. +1 por mencionar esto, ya que se pidieron las prácticas recomendadas. – Jonik

+0

Sí, realmente debería leer ese libro. – ripper234

0

Algo parecido a continuación pueden ayudar a su necesidades-

import java.util.Timer; 
import java.util.TimerTask; 

public class TimerGracefulShutdown { 
    public static void main(String[] args) throws InterruptedException { 
     //This is a synchronization helper class 
     SyncHelper syncHelper = new SyncHelper(); 

     TimerManager myTimerManager = new TimerManager(syncHelper); 

     //Try stopping timer after 5 seconds (it wont stop until the 30 seconds sleep of timertask does not finish) 
     Thread.currentThread().sleep(5000); 
     System.out.println("Going to stop my timer now"); 
     myTimerManager.stopTimer(); 
     System.out.println("Cancelled timer"); 
    } 
} 

class TimerManager { 

    SyncHelper syncHelper; 
    Timer timer; 

    public TimerManager(SyncHelper syncHelper) { 
     this.syncHelper = syncHelper; 
     startTimer(); 
    } 

    private void startTimer() { 
     timer = new Timer(true); 
     TimerTask myTask = new MyTimerTask(syncHelper); 
     timer.scheduleAtFixedRate(myTask, 0, 100000); 
    } 

    public void stopTimer() { 
     try { 
      syncHelper.testAndSetOrReset("acquire"); 
     } catch(Exception e) { 
      e.printStackTrace(); 
     } 

     //Shutdown the timer here since you know that your timertask is not executing right now. 
     timer.cancel(); 
     try { 
      syncHelper.testAndSetOrReset("release"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

class MyTimerTask extends TimerTask { 

    private SyncHelper syncHelper; 

    public MyTimerTask(SyncHelper syncHelper) { 
     this.syncHelper = syncHelper; 
    } 

    public void run() { 
     try { 
      syncHelper.testAndSetOrReset("acquire"); 
     } catch (Exception e1) { 
      e1.printStackTrace(); 
     } 

     System.out.println("Over here"); 
     try { 
      Thread.currentThread().sleep(30000); 
     } catch(Exception e) { 

     } 
     System.out.println("Done sleeping"); 

     //Finally release the helper. 
     try { 
      syncHelper.testAndSetOrReset("release"); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

} 

class SyncHelper { 

    private int index = 0; 

    public synchronized void testAndSetOrReset(String command) throws Exception { 

     if("acquire".equals(command)) { 
      if(index == 1) { 
       wait(); 
      } 
      index++; 
     } else if("release".equals(command)) { 
      index--; 
      notifyAll(); 
     } 
    } 
} 
+0

Debe usar 'Thread.sleep (. ..) 'en lugar de' Thread.currentThread(). sleep (...) 'porque es un método estático; su código podría tentarlo a hacer 'someOtherThread.sleep (...)' que no duerma 'someOtherThread'. – newacct

Cuestiones relacionadas