当前位置: 首页 > 知识库问答 >
问题:

如何确定取消的ScheduledFuture是否实际未取消?

卫嘉佑
2023-03-14

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

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

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

布尔值已取消 = future.cancel(false) 行。

取消之后,我必须根据提交的runnable是否实际运行来采取不同的操作。这里,让我们首先进入Oracle文档,了解< code>cancelled标志的含义:

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

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

这就是它所说的关于返回值的全部内容。似乎写这行文字的人在这里不确定错误的返回值,但我认为我可以接受它。

现在让我们关注一下这个案例,当它返回<code>true</code>时。这里有两种可能性:

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

我对这两种情况的发生都没问题,但我想知道哪一种实际发生了,并采取相应的行动。如果运行对象正在处理中,那么我可以接受它完成它的工作,我想等待它完成,然后做一件事。但是,如果它被取消并且根本不会运行,我想做另一件事。

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

共有2个答案

孙明德
2023-03-14

我最终为这一期写了类似这样的东西。源代码和一些单元测试可以在https://github.com/nuzayats/cancellabletaskexecutor找到

public class CancellableTaskExecutor {

    private final ScheduledExecutorService es;
    private final Logger log;

    /**
     * For a unit test to replicate a particular timing
     */
    private final Runnable hookBetweenCancels;

    public CancellableTaskExecutor(ScheduledExecutorService es, Logger log) {
        this(es, log, () -> {
            // nop
        });
    }

    // For unit tests
    CancellableTaskExecutor(ScheduledExecutorService es, Logger log, Runnable hookBetweenCancels) {
        this.es = es;
        this.log = log;
        this.hookBetweenCancels = hookBetweenCancels;
    }

    public Execution schedule(Runnable task, long delay, TimeUnit unit) {
        CancellableRunnable runnable = new CancellableRunnable(task);
        ScheduledFuture<?> future = es.schedule(runnable, delay, unit);
        return new Execution(future, runnable);
    }

    public class Execution {

        private final ScheduledFuture<?> future;
        private final CancellableRunnable runnable;

        private Execution(ScheduledFuture<?> future, CancellableRunnable runnable) {
            this.future = future;
            this.runnable = runnable;
        }

        /**
         * @return true when the task has been successfully cancelled and it's guaranteed that
         * the task won't get executed. otherwise false
         */
        public boolean cancel() {
            boolean cancelled = runnable.cancel();
            hookBetweenCancels.run();

            // the return value of this call is unreliable; see https://stackoverflow.com/q/55922874/3591946
            future.cancel(false);

            return cancelled;
        }
    }

    private class CancellableRunnable implements Runnable {

        private final AtomicBoolean cancelledOrStarted = new AtomicBoolean();
        private final Runnable task;

        private CancellableRunnable(Runnable task) {
            this.task = task;
        }

        @Override
        public void run() {
            if (!cancelledOrStarted.compareAndSet(false, true)) {
                return; // cancelled, forget about the task
            }
            try {
                task.run();
            } catch (Throwable e) {
                log.log(Level.WARNING, "Uncaught Exception", e);
            }
        }

        boolean cancel() {
            return cancelledOrStarted.compareAndSet(false, true);
        }
    }
}
艾灿
2023-03-14

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

  • A

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

重写此方法时,可以将可运行添加到集合中

然后,当取消schduledFuture时,您可以调用set.contains(map.get(未来)),它会告诉您是否执行了RunnableSchduledFuture映射到的)。

请注意,您的设置

 类似资料:
  • 问题内容: 我有一个调用一些不检查线程中断的代码。调用之后,该方法将立即抛出(如预期的那样)。但是,由于后台任务的代码从不检查其线程是否被中断,因此它很乐意继续执行。 是否有等待后台任务 实际 完成的标准方法?我希望显示“正在取消…”消息或某种类似的内容,直到任务终止为止。(我确信如果有必要,我总是可以在worker类中使用一个标志来完成此操作,只需寻找其他解决方案即可。) 问题答案: 我玩了一点

  • 问题内容: Javascript确认弹出窗口,我想显示“是,否”按钮,而不是“确定”和“取消”。 我已经使用了以下vbscript代码: 这仅适用于IE,在FF和Chrome中,但无效。 是否有任何工作来实现此目的? 我也想更改弹出窗口的标题,如在IE中显示“ Windows Internet Explorer”,我想在这里显示我自己的应用程序名称。 问题答案: 不幸的是,没有跨浏览器的支持来打开

  • 有没有办法知道实体是否是从数据库中读取的? 这个问题与如何知道一个分离的JPA实体是否已经被持久化有关?。但是检查其主键的变通方法没有回答我的问题。对于从导入文件中读取主键的实体来说,它是不起作用的。 将问题引申如下: JPA实现如何确定是否要插入或更新实体?

  • 问题内容: Javascript确认弹出窗口,我想显示“是,否”按钮,而不是“确定”和“取消”。 我已经使用了以下vbscript代码: 这仅适用于IE,在FF和Chrome中,但无效。 是否有任何工作来实现此目的? 我也想更改弹出窗口的标题,如在IE中显示“ Windows Internet Explorer”,我想在这里显示我自己的应用程序名称。 问题答案: 不幸的是,没有跨浏览器的支持来打开

  • 问题内容: 未定义CSS 和属性时,如何获取元素的实际字体和字体大小? 例如,JavaScript代码段 不返回任何值。假设CSS尚未将样式应用于任何地方,这非常明显。但是,当然,使用某种字体来呈现文本,可能是系统字体或Web浏览器默认字体。 例如,JavaScript可以获取该渲染字体吗? 问题答案: 我建议这个功能: 用法: 注意:不适用于IE8。

  • 问题内容: 我是Angular(和JS)的新手,只是有些困惑。 我用以下命令启动计时器: 据我了解,这是一个“承诺”。 我希望能够检查是否计时器正在运行和已经例外,如果我曾经 那么会,我可以检查那个。 似乎并非如此。 我是否必须显式销毁诺言(对计时器已取消的诺言是什么?)。如果是这样,我将如何&然后必须将其显式设置为? 我 认为 我应该使用,但不能100%地确定,因为之后还是非空的。 谢谢你的帮助