使用ScheduledExecutorService启动和停止计时器 [英] using ScheduledExecutorService to start and stop timer

查看:1311
本文介绍了使用ScheduledExecutorService启动和停止计时器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我需要输入一些启动和停止定时器的代码。这不是一个周期性的定时器。该代码在启动定时器之前停止。所以,有效的每一个开始都是一个重启()。我正在寻找使用ScheduledExecutorService执行此操作的正确方法。这是我想出来的。寻找对我所缺少的东西的评论和洞察力:

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

private boolean startTimer(){
try {
if(_TimerFuture!= null){
//取消未来任务的执行(TimerPopTask())
//如果任务已经运行,不要中断它。
_TimerFuture.cancel(false);
}

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

private boolean stopTimer(){
try {
if(_TimerFuture!= null){
//取消执行的未来任务(TimerPopTask())
//如果任务已经在运行,请在此处中断。
_TimerFuture.cancel(true);
}

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

私有类TimerPopTask实现Runnable {
public void run(){
TimerPopped();
}
}

public void TimerPopped(){
// Do Something
}

tia,
ruble

解决方案

像一个问题:

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

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

既然你是传递错误以取消,如果任务已经在运行,旧的 _TimerFuture 可能不会被取消。一个新的创建无论如何(但它不会同时运行,因为您的 ExecutorService 具有固定的线程池大小为1)。无论如何,在调用startTimer()时,这听起来不像您想要重新启动定时器的行为。



我将重新构建一下。我会使 TimerPopTask 实例成为你取消的东西,只要一次,我将离开 ScheduledFutures 创建:

 私有类TimerPopTask实现Runnable {
//易于线程安全
private volatile boolean isActive = true;
public void run(){
if(isActive){
TimerPopped();
}
}
public void deactivate(){
isActive = false;
}
}

那么我会保留 TimerPopTask 而不是 ScheduledFuture 的实例,然后重新排列startTimer方法:

  private TimerPopTask timerPopTask; 

private boolean startTimer(){
try {
if(timerPopTask!= null){
timerPopTask.deactivate();
}

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

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

如果您真的希望在当前计时器到期之前需要重新启动计时器,则可能需要调整线程数量:

 私有ScheduledExecutorService _Timer = Executors.newScheduledThreadPool(5); 

您可能需要使用混合方法,保持对我所描述的当前TimerPopTask的引用,也可以使用当前的ScheduledFuture,尽可能的取消它并释放线程,如果可能的话,理解它不能保证取消。



(注意:这一切都假定startTimer()和stopTimer()方法调用仅限于单个主线程,只有 TimerPopTask 实例在线程之间共享,否则您需要额外的保护措施。 / p>

From my readings, it seems that ScheduledExecutorService is the right way to start and stop timers in Java.

I need to port some code that starts and stops a timer. This is not a periodic timer. This code, stops the timer before starting it. So, effectively every start is really a restart(). I am looking for the right way to do this using the ScheduledExecutorService. Here is what I came up with. Looking for comments and insight on things I am missing:

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, rouble

解决方案

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.)

这篇关于使用ScheduledExecutorService启动和停止计时器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆