等待计时器在 Java 中完成

2022-09-04 01:02:01

我正在使用java.util.Timer来调度一个定期任务。有一次,我想关闭它,然后等待它完成

Timer.cancel() 将阻止任何未来的任务运行。如何确保当前未运行任何任务(或者如果正在运行,请等待它们?

我可以引入外部同步机制,但我不明白它们如何涵盖所有情况。例如,如果我在任务中的某个监视器上进行同步,我仍然会错过任务刚刚开始执行但未采用监视器的情况。

等到所有任务(包括当前正在运行的任务)真正完成时,建议采用什么做法?


答案 1

最好使用 ScheduledExecutorService 而不是 Timer 来计划定期任务。ScheduledExecutorService 提供了一个 shutdown() 方法,该方法将执行任何挂起的任务。然后,您可以调用 awaitTermination() 来等待 shutdown() 完成。


答案 2

像下面这样的东西可能会帮助你的需求 -

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