using ScheduledExecutorService to start and stop timer

别来无恙 提交于 2019-12-04 07:30:25

This looks like a problem:

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

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

Since you're passing a false to cancel, the old _TimerFuture may not get cancelled if the task is already running. A new one gets created anyway (but it won't run concurrently because your ExecutorService has a fixed thread pool size of 1). In any case, that doesn't sound like your desired behavior of restarting a timer when startTimer() is called.

I would rearchitect a bit. I would make the TimerPopTask instance be the thing you "cancel", and I would leave the ScheduledFutures alone once they are created:

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

then I would retain the instance of TimerPopTask rather than the instance of ScheduledFuture and rearrange startTimer method thusly:

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

(Similar modification to stopTimer() method.)

You may want to crank up the number of threads if you truly anticipate needing to 'restart' the timer before the current timer expires:

private ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5);

You may want to go with a hybrid approach, keeping references to both the current TimerPopTask as I described and also to the current ScheduledFuture and make the best effort to cancel it and free up the thread if possible, understanding that it's not guaranteed to cancel.

(Note: this all assumes startTimer() and stopTimer() method calls are confined to a single main thread, and only the TimerPopTask instances are shared between threads. Otherwise you'll need additional safeguards.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!