我有一项任务,要求我安排任务并在发生特定事件时将其删除。我正在使用ScheduledThreadPoolExecutor来安排任务,这非常简单。但是,我找到了两种取消待处理项目的方法,它们看起来有点奇怪。
我很好奇他们是否有生产质量。如果他们都没有,那你有什么建议?
这是我所做的一个骨架:
private final ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);
public void doStuff() {
//...
scheduler.schedule(new Runnable() {/*...*/}, 10, TimeUnit.MILISECONDS)
}
public void actOnEvent() {
cancelPendingItems();
doMoreStuff();
}
public void cancelPendnigItems() {
// TODO implement me
}
这是候选人1:
public void cancelPendingItems() {
scheduler.getQueue().clear();
}
这是候选人2:
public void cancelPendingItems() {
for (Runnable task : scheduler.getQueue()) {
scheduler.remove(task);
}
}
两者看起来都像是黑客,因为它们依赖于ScheduledExecutor接口中未指定的ScheduledThreadPoolExecutor.queue属性。我有点担心我可能会违反ScheduledThreadPoolExecutor的不变量而且我会发现它太迟了。
那么,这些片段是否会按照我的要求去做?有没有更好/更清洁的方法呢?
答案 0 :(得分:10)
请注意,ScheduledExecutorService.schedule
会返回ScheduledFuture
。只需存储这些,并在调用cancel方法时,对存储的期货使用cancel
方法取消其未来的迭代。
答案 1 :(得分:4)
我会使用List<Future>
:
private final List<Future> futures = ...
public void doStuff() {
futures.add(scheduler.schedule(new Runnable() {/*...*/}, 10,
TimeUnit.MILISECONDS));
}
public void cancelPendingItems() {
for(Future future: futures)
future.cancel(true);
futures.clear();
}
答案 2 :(得分:2)
Future.cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。如果任务已经完成,已经取消或由于某些其他原因无法取消,则此尝试将失败。如果成功,并且在调用cancel时此任务尚未启动,则此任务永远不会运行。如果任务已经启动,则mayInterruptIfRunning参数确定执行此任务的线程是否应该在尝试停止任务时被中断。
或者您也可以使用ScheduledThreadPoolExecutor#shutdownNow
尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。
除了尽力尝试停止处理主动执行任务之外,没有任何保证。此实现通过Thread.interrupt()取消任务,因此任何无法响应中断的任务都可能永远不会终止。
因此,您需要处理InterruptedException
以允许安全退出正在被取消的线程。