java - 如何识别被取消的 ScheduledFuture 是否真的没有被取消?

标签 java concurrency scheduled-tasks java.util.concurrent

我正在使用 ScheduledExecutorService 并提交这样的任务:

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

然而,某个事件可能会在不确定的时间后发生,这表明不再需要该任务。所以我需要取消这个任务,我正在使用

boolean canceled = future.cancel(false) 行。

取消后,我必须根据提交的可运行对象是否实际运行来采取不同的操作。让我们首先进入 Oracle 文档并阅读 cancelled 标志的含义:

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

Returns: false if the task could not be cancelled, typically because it has already completed normally; true otherwise

这就是关于返回值的全部内容。似乎编写此文本行的人不确定此处的 false 返回值,但我想我可以接受。

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

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

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

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

最佳答案

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

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

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

覆盖此方法时,您可以添加 Runnable给你的Set<Runnable> .

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


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

关于java - 如何识别被取消的 ScheduledFuture 是否真的没有被取消?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55922874/

相关文章:

多线程环境中的 Java 对象构造

sql-server - 如果通过PSD脚本执行Powershell脚本的SQL 2005作业显示失败,则PS脚本失败

java - Spring任务执行器和调度器

java - 循环绘制不同的图像?

java - Java 中的引用计数

java - 矩形 Java Swing 单选按钮?

C++11 原子库 std::compare_and_exchange 语义

xml - 使用 '' #text'' 和 InnerText XML (Powershell) 之间的区别

java - 随机生成器似乎没有生成某些数字 : is my code wrong or is it a feature of objects of type Random?

java - 如何使用 BST 实现哈希表?