【问题标题】:How to cancel pending items from a ScheduledThreadPoolExecutor?如何从 ScheduledThreadPoolExecutor 取消挂起的项目?
【发布时间】:2012-09-24 16:38:16
【问题描述】:

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

那么,这些 sn-ps 会做我想让他们做的事吗?有没有更好/更清洁的方法?

【问题讨论】:

    标签: java multithreading executors


    【解决方案1】:

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

    【讨论】:

    • Web 应用程序应该将这些存储在哪里?是否可以将它们存储在数据库中?我提前几天安排活动,有些活动到时候就不再相关了。无论如何我必须运行它们吗?或者有什么方法可以将未来保存在数据库中以便我可以取消事件?
    【解决方案2】:

    我会使用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();
    }
    

    【讨论】:

    • 谢谢!幸运的是,它适合我的实际问题,因为没有太多可能的任务,所以这个清理会相当快。这对于我们资源受限的应用程序很重要。
    【解决方案3】:

    Future.cancel(boolean mayInterruptIfRunning)

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

    或者你也可以使用ScheduledThreadPoolExecutor#shutdownNow

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

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

    所以你需要处理InterruptedException 以允许被取消的线程安全退出。

    【讨论】:

      猜你喜欢
      • 2019-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-01-10
      • 2015-01-28
      • 2012-06-03
      • 1970-01-01
      相关资源
      最近更新 更多