如何识别是否取消了ScheduledFuture实际上没有被取消?

问题描述 投票:5回答:1

我正在使用ScheduledExecutorService并提交类似的任务:

future = scheduledExecutorService.schedule(myRunnableTask, delay, timeunit)

但是,在无限期的时间之后可能会发生某个事件,这表示不再需要此任务。所以我需要取消这个任务,我正在使用

boolean cancelled = future.cancel(false)线。

取消后,我必须采取不同的操作,具体取决于提交的runnable是否实际运行。在这里让我们首先跳转到Oracle文档并阅读cancelled标志的含义:

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)

返回:如果无法取消任务,则返回false,通常是因为它已经正常完成;否则为真

这就是关于回报价值的全部内容。好像写这篇文章的人不确定false这里的返回值,但我想我可以接受它。

让我们现在关注案例,当它返回true。这里有两种可能性:

  1. 该任务实际上已取消,并且可运行从未运行过。
  2. runnable正在运行,因此无法取消。 (除非我做一些线程中断逻辑,我真的不想这样做)

我对这两种情况都很好,但我想知道哪一个实际发生并采取相应的行动。如果runnable正在进行中,那么我可以完成它的工作,我想等待它完成然后做一件事。但如果它被取消并且根本不会运行,我想做另一件事。

你能推荐一个方法吗?我错过了什么吗?

java concurrency scheduled-tasks java.util.concurrent
1个回答
1
投票

您可以通过以下方式实现目标:

  • 一个Set<Runnable>,它跟踪已经开始由线程池执行的Runnables。
  • Map<ScheduledFuture<?>, Runnable>映射到各自的ScheduledFuture<?>Runnable。 在安排任务后,你应该立即将ScheduledFuture及其各自的Runnable添加到Map。 如果这个插入Map是通过调度任务本身原子地执行,那么你可以避免ScheduledFuture从未被添加到Map的边缘情况,即使它被取消。

我建议将你的ScheduledExecutorService改为ScheduledThreadPoolExecutor,这将允许你覆盖它的beforeExecute(Thread, Runnable)方法;在已经为池分配了将执行任务的线程之后,在池运行任务之前立即调用此方法。

覆盖此方法时,可以将Runnable添加到Set<Runnable>

然后,当一个ScheduledFuture被取消时,你可以调用set.contains(map.get(future)),它告诉你是否执行了RunnableScheduledFuture映射到)。


请注意,您的Set<Runnable>Map<ScheduledFuture<?>, Runnable>实现可能必须是线程安全的,以避免可能的竞争条件。

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.