Ожидание завершения таймера в Java - PullRequest
10 голосов
/ 24 августа 2009

Я использую java.util.Timer , чтобы запланировать периодическое задание. В какой-то момент я бы хотел выключить его и дождаться, пока он завершит .

Timer.cancel () предотвратит запуск любых будущих задач. Как мне убедиться, что какие-либо задачи не выполняются в данный момент (или подождать их, если они есть?)

Я могу представить внешние механизмы синхронизации, но я не понимаю, как они могут охватывать все случаи. Например, если я выполняю синхронизацию на каком-либо мониторе в рамках задачи, я все равно упускаю случай, когда задача только начала выполняться, но не заняла монитор.

Какова рекомендуемая практика ожидания, пока все задачи действительно не будут выполнены, включая запущенные в данный момент?

Ответы [ 2 ]

21 голосов
/ 24 августа 2009

Было бы лучше использовать ScheduledExecutorService вместо таймера для планирования вашей периодической задачи. ScheduledExecutorService предоставляет метод shutdown (), который будет выполнять любые отложенные задачи. Затем вы можете вызвать awaitTermination (), чтобы дождаться завершения shutdown ().

0 голосов
/ 24 августа 2009

Нечто подобное может помочь вашим потребностям-

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();
        }
    }
}
...