使用ScheduledExecutorService启动和停止计时器 [英] using ScheduledExecutorService to start and stop timer
问题描述
从我的读数看,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屋!