2009-08-24 14 views
7

J'utilise java.util.Timer pour planifier une tâche périodique. À un moment donné, je voudrais le fermer, et l'attendre pour finir.En attente de la fin d'un minuteur en Java

Timer.cancel() empêche l'exécution de toute tâche future. Comment est-ce que je m'assure que n'importe quelles tâches n'existent pas actuellement (ou les attendez si elles sont?)

Je peux introduire des mécanismes externes de synchronisation, mais je ne vois pas comment elles peuvent couvrir tous les cas. Par exemple, si je synchronise sur un moniteur dans la tâche, je manque toujours le cas lorsque la tâche a commencé à s'exécuter mais n'a pas pris le moniteur.

Quelle est la pratique recommandée pour attendre que toutes les tâches soient réellement effectuées, y compris les tâches en cours d'exécution?

Répondre

18

Vous feriez mieux d'utiliser un ScheduledExecutorService au lieu d'un temporisateur pour planifier votre tâche périodique. ScheduledExecutorService fournit une méthode shutdown() qui exécutera toutes les tâches en attente. Vous pouvez ensuite appeler waitTermination() pour attendre la fin de shutdown().

+0

+1. Ou, si vous devez utiliser un 'Timer' pour une raison quelconque, alors vous pouvez utiliser une condition (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ Condition.html) pour synchroniser deux threads sur un événement (comme l'achèvement de la tâche planifiée). –

+2

Ouais, l'article 68 dans Effective Java (2e éd) recommande ScheduledThreadPoolExecutor comme un remplacement plus flexible pour Timer. +1 pour mentionner cela, car les pratiques recommandées ont été demandées. – Jonik

+0

Oui, je devrais vraiment lire ce livre. – ripper234

0

Quelque chose comme ci-dessous peut aider vos besoins-

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

Vous devriez utiliser 'Thread.sleep (. ..) 'au lieu de' Thread.currentThread(). sleep (...) 'parce que c'est une méthode statique; votre code pourrait vous tenter de faire 'someOtherThread.sleep (...)' qui ne dort pas 'someOtherThread'. – newacct