10

我有一项任务需要我安排任务并在发生特定事件时将其删除。我正在使用 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);
    }
}

两者对我来说都像是 hack,因为它们依赖于 ScheduledExecutor 接口中未指定的 ScheduledThreadPoolExecutor.queue 属性。我有点担心我可能会违反 ScheduledThreadPoolExecutor 的不变量,我会发现它太晚了。

那么,这些片段会做我想让他们做的事情吗?有没有更好/更清洁的方法来做到这一点?

4

3 回答 3

11

请注意,ScheduledExecutorService.schedule返回一个ScheduledFuture. 只需存储这些,当您的取消方法被调用时,使用cancel存储的期货上的方法来取消它们未来的迭代。

于 2012-09-24T16:42:05.660 回答
5

我会使用一个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();
}
于 2012-09-24T16:42:41.977 回答
2

Future.cancel(boolean mayInterruptIfRunning)

尝试取消此任务的执行。如果任务已完成、已被取消或由于其他原因无法取消,则此尝试将失败。如果成功,并且在调用取消时此任务尚未启动,则此任务不应该运行。如果任务已经开始,则 mayInterruptIfRunning 参数确定是否应该中断执行该任务的线程以尝试停止该任务。

或者你也可以使用ScheduledThreadPoolExecutor#shutdownNow

尝试停止所有正在执行的任务,停止等待任务的处理,并返回等待执行的任务列表。

除了尽最大努力停止处理正在执行的任务之外,没有任何保证。此实现通过 Thread.interrupt() 取消任务,因此任何未能响应中断的任务可能永远不会终止。

因此,您需要处理InterruptedException以允许安全退出正在取消的线程。

于 2012-09-24T16:48:09.723 回答