2010-06-23 33 views
5

Según mis lecturas, parece que ScheduledExecutorService es la forma correcta de iniciar y detener temporizadores en Java.usando ScheduledExecutorService para iniciar y detener el temporizador

Necesito cargar un código que inicia y detiene un temporizador. Este no es un temporizador periódico. Este código, detiene el temporizador antes de iniciarlo. Entonces, efectivamente cada inicio es realmente un reinicio(). Estoy buscando la forma correcta de hacerlo utilizando el ScheduledExecutorService. Esto es lo que se me ocurrió. En busca de comentarios y visión sobre las cosas me faltan:

ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(1); 
ScheduledFuture<?> _TimerFuture = null; 

private boolean startTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, do not interrupt it. 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private boolean stopTimer() { 
    try { 
     if (_TimerFuture != null) { 
      //cancel execution of the future task (TimerPopTask()) 
      //If task is already running, interrupt it here. 
      _TimerFuture.cancel(true); 
     } 

     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

private class TimerPopTask implements Runnable { 
    public void run() { 
     TimerPopped(); 
    } 
} 

public void TimerPopped() { 
    //Do Something 
} 

tia, rublo

+0

Código tal como está escrito no compilará: _batchTimer en startTimer() no está declarado en ningún lado. Sería útil si pudiera entrar un poco más en detalle sobre los comportamientos esperados: ¿cuáles son los valores de retorno de startTimer y stopTimer? ¿Por qué quieres que start/stopTimer bloquee potencialmente las llamadas? – Sbodd

+0

@Sbodd, cuando voy a iniciar un temporizador, si ya hay un temporizador en ejecución, quiero detenerlo, de modo que no tengo dos temporizadores apareciendo al mismo tiempo. Creo que en lugar de get() allí, solo necesito llamar a cancel() en la instancia futura. – rouble

Respuesta

3

Esto parece un problema:

private boolean startTimer() { 
    // ...... 
     if (_TimerFuture != null) { 
      _TimerFuture.cancel(false); 
     } 

     _TimerFuture = _Timer.schedule(new TimerPopTask(), 
             TIMER_IN_SECONDS, 
             TimeUnit.SECONDS); 
    // ...... 
} 

Puesto que usted está pasando un falso cancelar, la viejo _TimerFuture puede no ser cancelado si la tarea ya se está ejecutando. Se creará uno nuevo de todos modos (pero no se ejecutará al mismo tiempo porque su ExecutorService tiene un tamaño de grupo de subprocesos fijo de 1). En cualquier caso, eso no suena como el comportamiento deseado de reiniciar un temporizador cuando se invoca startTimer().

Me gustaría volver a crear un poco. Me hago la instancia TimerPopTask ser la cosa que "Cancelar", y que dejaría el ScheduledFutures solo una vez que se crean:

private class TimerPopTask implements Runnable { 
    //volatile for thread-safety 
    private volatile boolean isActive = true; 
    public void run() { 
     if (isActive){ 
      TimerPopped(); 
     } 
    } 
    public void deactivate(){ 
     isActive = false; 
    } 
} 

entonces conservarían la instancia de TimerPopTask en lugar de la instancia de ScheduledFuture y reorganizar startTimer método de esta manera:

(. método de modificación similares a stopTimer())
private TimerPopTask timerPopTask; 

private boolean startTimer() { 
    try { 
     if (timerPopTask != null) { 
      timerPopTask.deactivate(); 
     } 

     timerPopTask = new TimerPopTask(); 
     _Timer.schedule(timerPopTask, 
         TIMER_IN_SECONDS, 
         TimeUnit.SECONDS); 
     return true; 
    } catch (Exception e) { 
     return false; 
    } 
} 

Es posible que desee subir el número de hilos si realmente anticipar nee ding a 'reinicio' el temporizador antes de que el temporizador expire:

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5); 

es posible que desee ir con un enfoque híbrido, manteniendo referencias tanto a la TimerPopTask actual como he descrito, y también a la ScheduledFuture actual y hacer el mejor Esfuerzo para cancelarlo y liberar el hilo si es posible, entendiendo que no se garantiza que se cancele.

(Nota:.. Todo esto supone startTimer() y stopTimer() las llamadas a métodos se limitan a un solo hilo principal, y sólo los TimerPopTask casos son compartidos entre los hilos de lo contrario necesitarás salvaguardias adicionales)

+0

buen punto. Déjame preguntarte esto, decir que una tarea se estaba ejecutando. Se crea una nueva tarea y se programa para ejecutar TIMER_IN_SECONDS segundos más tarde. ¿Cuándo comienza esta vez (TIMER_IN_SECONDS segundos)? ¿Comienza en ese momento, cuando se llama schedule() O comienza cuando hay un hilo libre en el grupo de subprocesos? – rouble

+0

El retraso TIMER_IN_SECONDS comienza 'ahora' a la derecha cuando se llama a schedule().La tarea está garantizada para comenzar no antes de la demora, sin embargo, puede comenzar más tarde (dependiendo en parte de la disponibilidad de subprocesos). Desde el javadoc para ScheduledThreadPoolExecutor: "Las tareas retrasadas se ejecutan tan pronto como están habilitadas, pero sin garantías en tiempo real sobre cuándo, una vez habilitadas, comenzarán". –

Cuestiones relacionadas