2009-08-24 9 views
7

Ich verwende java.util.Timer, um eine periodische Aufgabe zu planen. An einem Punkt möchte ich es herunterfahren und warten, bis es beendet.Warten auf das Beenden eines Timers in Java

Timer.cancel() verhindert, dass zukünftige Aufgaben ausgeführt werden. Wie stelle ich sicher, dass keine Aufgaben im Moment ausgeführt werden (oder auf sie warten, wenn sie es sind?)

Ich kann externe Synchronisationsmechanismen einführen, aber ich sehe nicht, wie sie alle Fälle abdecken können. Zum Beispiel, wenn ich auf einem Monitor innerhalb der Aufgabe zu synchronisieren, vermisse ich immer noch den Fall, wenn die Aufgabe gerade gestartet, aber nicht den Monitor zu nehmen.

Was ist die empfohlene Vorgehensweise, um zu warten, bis alle Aufgaben ausgeführt wurden, einschließlich aktuell ausgeführter Aufgaben?

Antwort

18

Sie würden besser einen ScheduledExecutorService anstelle eines Timers verwenden, um Ihre periodische Aufgabe zu planen. ScheduledExecutorService stellt eine shutdown() -Methode bereit, die alle ausstehenden Aufgaben ausführt. Sie können dann awaistTermination() aufrufen, um auf das Beenden von shutdown() zu warten.

+0

+1 helfen. Oder, wenn Sie aus irgendeinem Grund einen 'Timer' verwenden müssen, können Sie eine Bedingung verwenden (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ Condition.html), um zwei Threads für ein Ereignis zu synchronisieren (z. B. die Fertigstellung der geplanten Aufgabe). –

+2

Ja, Element 68 in Effective Java (2. Ausgabe) empfiehlt ScheduledThreadPoolExecutor als flexibleren Ersatz für Timer. +1 für das Erwähnen dieser, als empfohlene Praktiken wurden gefragt. – Jonik

+0

Ja, ich sollte dieses Buch wirklich lesen. – ripper234

0

So etwas wie unten können Sie Ihre bedarfs-

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

Sie sollten 'Thread.Sleep (. ..) '' anstelle von 'Thread.currentThread(). sleep (...)' weil es eine statische Methode ist; Ihr Code könnte Sie dazu verleiten, 'someOtherThread.sleep (...)' zu machen, das nicht 'someOtherThread' schläft. – newacct

Verwandte Themen