如何从ScheduledThreadPoolExecutor中取消待处理的项目?

时间:2012-09-24 16:38:16

标签: java multithreading executors

我有一项任务,要求我安排任务并在发生特定事件时将其删除。我正在使用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的不变量而且我会发现它太迟了。

那么,这些片段是否会按照我的要求去做?有没有更好/更清洁的方法呢?

3 个答案:

答案 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以允许安全退出正在被取消的线程。