2009-08-24 15 views
7

Używam java.util.Timer do zaplanowania zadania okresowego. W pewnym momencie chciałbym go wyłączyć i czekać na zakończenie.Oczekiwanie na zakończenie Timera w Javie

Timer.cancel() uniemożliwi uruchomienie jakichkolwiek przyszłych zadań. Jak mogę się upewnić, że jakiekolwiek zadania nie są w danej chwili uruchomione (lub czekać na nie, jeśli są?)

Mogę wprowadzić zewnętrzne mechanizmy synchronizacji, ale nie widzę, w jaki sposób mogą one pokryć wszystkie przypadki. Na przykład, jeśli zsynchronizuję się z jakimś monitorem w ramach zadania, nadal tęsknię za przypadkiem, gdy zadanie właśnie rozpoczęło wykonywanie, ale nie wziął monitora.

Jaka jest zalecana praktyka oczekiwania na wykonanie wszystkich zadań, w tym aktualnie uruchomionych zadań?

Odpowiedz

18

Lepiej byłoby użyć ScheduledExecutorService zamiast Zegara, aby zaplanować okresowe zadanie. ScheduledExecutorService udostępnia metodę shutdown(), która wykonuje wszystkie oczekujące zadania. Następnie możesz wywołać funkcję awaitTermination(), aby poczekać, aż zamknięcie() zostanie zakończone.

+0

+1. Lub, jeśli z jakiegoś powodu musisz użyć 'Zegara', możesz użyć warunku (http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/locks/ Condition.html), aby zsynchronizować dwa wątki w zdarzeniu (takie jak ukończenie zaplanowanego zadania). –

+2

Tak, pozycja 68 w Effective Java (wydanie drugie) zaleca ScheduledThreadPoolExecutor jako bardziej elastyczny zamiennik Timera. +1 za wzmiankę o tym, ponieważ poproszono o zalecane praktyki. – Jonik

+0

Tak, naprawdę powinienem przeczytać tę książkę. – ripper234

0

Coś jak poniżej może pomóc needs-

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

Powinieneś użyć 'Thread.sleep (. ..) 'zamiast' Thread.currentThread(). sleep (...) 'ponieważ jest to metoda statyczna; twój kod może skusić cię do zrobienia 'someOtherThread.sleep (...)' który nie zasypia 'someOtherThread'. – newacct

Powiązane problemy