使用ScheduledExecutorService启动和停止计时器

时间:2010-06-23 17:38:19

标签: java multithreading design-patterns timer executorservice

从我的读数来看,似乎ScheduledExecutorService是在Java中启动和停止计时器的正确方法。

我需要移植一些启动和停止计时器的代码。这不是周期性计时器。此代码在启动之前停止计时器。所以,实际上每次启动都是一次重启()。我正在寻找使用ScheduledExecutorService执行此操作的正确方法。这就是我想出的。寻找有关我缺少的事情的评论和见解:

ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(1);
ScheduledFuture<?> _TimerFuture = null;

private boolean startTimer() {
    try {
        if (_TimerFuture != null) {
            //cancel execution of the future task (TimerPopTask())
            //If task is already running, do not interrupt it.
            _TimerFuture.cancel(false);
        }

        _TimerFuture = _Timer.schedule(new TimerPopTask(), 
                                       TIMER_IN_SECONDS, 
                                       TimeUnit.SECONDS);
        return true;
    } catch (Exception e) {
        return false;
    }
}

private boolean stopTimer() {
    try {
        if (_TimerFuture != null) {
            //cancel execution of the future task (TimerPopTask())
            //If task is already running, interrupt it here.
            _TimerFuture.cancel(true);
        }

        return true;
    } catch (Exception e) {
        return false;
    }
}

private class TimerPopTask implements Runnable  {  
    public void run ()   {  
        TimerPopped();
    }  
}

public void TimerPopped () {
    //Do Something
}

TIA, 卢布

1 个答案:

答案 0 :(得分:3)

这看起来像一个问题:

private boolean startTimer() {
    // ......
        if (_TimerFuture != null) {
            _TimerFuture.cancel(false);
        }

        _TimerFuture = _Timer.schedule(new TimerPopTask(), 
                                       TIMER_IN_SECONDS, 
                                       TimeUnit.SECONDS);
    // ......
}

由于您要传递false以取消,因此如果任务已在运行,则旧_TimerFuture可能不会被取消。无论如何都会创建一个新的(但它不会同时运行,因为您的ExecutorService具有固定的线程池大小为1)。在任何情况下,这听起来都不像你在调用startTimer()时重启计时器的行为。

我会重新解构一下。我会让TimerPopTask实例成为你“取消”的东西,并且我会在ScheduledFutures创建后留下private class TimerPopTask implements Runnable { //volatile for thread-safety private volatile boolean isActive = true; public void run () { if (isActive){ TimerPopped(); } } public void deactivate(){ isActive = false; } }

TimerPopTask

然后我会保留ScheduledFuture的实例,而不是private TimerPopTask timerPopTask; private boolean startTimer() { try { if (timerPopTask != null) { timerPopTask.deactivate(); } timerPopTask = new TimerPopTask(); _Timer.schedule(timerPopTask, TIMER_IN_SECONDS, TimeUnit.SECONDS); return true; } catch (Exception e) { return false; } } 的实例,并重新安排startTimer方法:

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5);

(对stopTimer()方法的类似修改。)

如果你真的希望在当前计时器到期之前需要“重启”计时器,你可能想要提高线程数:

TimerPopTask

您可能想要去的混合方式,保持引用到双方当前TimerPopTask为我描述,也对当前ScheduledFuture,并取消它并释放线程,如果可能最好的努力,理解,它不能保证取消。

(注意:这一切都假定startTimer所()和stopTimer()方法调用被限制在一个单一的主线程,并且只有{{1}}实例线程之间共享否则就需要额外的保护措施。)< / p>