2009-08-24 9 views
7

Sto utilizzando java.util.Timer per pianificare un'attività periodica. A un certo punto, mi piacerebbe spegnerlo, e attendere che finisca.In attesa del completamento di un timer in Java

Timer.cancel() impedirà l'esecuzione di attività future. Come posso assicurarmi che alcune attività non siano in esecuzione al momento (o aspettarle se lo sono?)

Posso introdurre meccanismi di sincronizzazione esterni, ma non vedo come possano coprire tutti i casi. Ad esempio, se eseguo la sincronizzazione su alcuni monitor all'interno dell'attività, mi manca ancora il caso quando l'attività ha appena iniziato ad essere eseguita ma non ha preso il monitor.

Qual è la pratica consigliata per l'attesa fino a quando tutte le attività vengono effettivamente eseguite, incluse le attività attualmente in esecuzione?

risposta

18

È preferibile utilizzare un ScheduledExecutorService anziché un timer per pianificare l'attività periodica. ScheduledExecutorService fornisce un metodo shutdown() che eseguirà tutte le attività in sospeso. È quindi possibile chiamare awaitTermination() per attendere la chiusura di shutdown().

+0

+1. Oppure, se per qualche motivo devi usare un 'Timer', puoi usare una Condizione (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ Condition.html) per sincronizzare due thread su un evento (ad esempio il completamento dell'attività pianificata). –

+2

Sì, la voce 68 in Java efficace (2a edizione) consiglia ScheduledThreadPoolExecutor come sostituzione più flessibile per Timer. +1 per aver menzionato questo, come richiesto per le pratiche raccomandate. – Jonik

+0

Sì, dovrei davvero leggere quel libro. – ripper234

0

Qualcosa di simile al di sotto potrebbe aiutare il vostro esigenze-

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

Dovresti usare 'Thread.sleep (. ..) 'invece di' Thread.currentThread(). sleep (...) 'perché è un metodo statico; il tuo codice potrebbe indurti a fare 'someOtherThread.sleep (...)' che non dorme 'someOtherThread'. – newacct