Waiting for a Timer to finish in Java

2019-02-12 20:24发布

问题:

I'm using java.util.Timer to schedule a periodic task. At one point, I'd like to shut it down, and wait for it to finish.

Timer.cancel() will prevent any future tasks from running. How do I make sure any tasks are not running at the moment (or wait for them if they are?)

I can introduce external synchronization mechanisms, but I don't see how they can cover all cases. For example, if I synchronize on some Monitor within the task, I still miss the case when the task just started executing but didn't take the monitor.

What is the recommended practice for waiting until all tasks are really done, including currently running tasks?

回答1:

You would be better using an ScheduledExecutorService instead of a Timer to schedule your periodic task. ScheduledExecutorService provides a shutdown() method that will execute any pending tasks. You can then call awaitTermination() to wait for shutdown() to finish.



回答2:

Something like below might help your 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();
        }
    }
}