我有一个任务,要求我安排任务,并在某个事件发生时将其删除。我使用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);
}
}
在我看来,这两者都像是黑客攻击,因为它们依赖于ScheduledPhreadPoolExecutor.queue属性,而该属性没有在ScheduledExecutor接口中指定。我有点担心我可能会违反ScheduledThreadPoolExecutor的一个不变量,而且我会发现它太晚了。
那么,这些片段会做我想让它们做的事情吗?有更好/更干净的方法吗?
ScheduledExecutorService.schedule
返回一个ScheduledFuture
。只需存储这些,当调用cancel方法时,对存储的期货使用cancel
方法来取消它们未来的迭代。
我会使用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();
}
Future.cancel(boolean mayInterruptIfRunning)
尝试取消执行此任务。如果任务已完成、已取消或由于其他原因无法取消,则此尝试将失败。如果成功,并且在调用cancel时此任务尚未启动,则不应运行此任务。如果任务已经启动,那么mayInterruptIfRunning参数确定是否应该中断执行此任务的线程以尝试停止任务。
或者您也可以使用ScheduledThreadPoolExecutor#shutdownNow
尝试停止所有正在执行的任务,停止处理等待的任务,并返回等待执行的任务列表。
除了尽力停止处理正在执行的任务之外,没有任何保证。此实现通过Thread.interrupt()取消任务,因此任何未能响应中断的任务都可能永远不会终止。
因此,您需要处理InterruptedException
以允许被取消的线程安全退出。