为了账号安全,请及时绑定邮箱和手机立即绑定

如何识别已取消的 ScheduledFuture 是否实际上未取消?

如何识别已取消的 ScheduledFuture 是否实际上未取消?

红糖糍粑 2022-11-02 10:29:40
我正在使用 ScheduledExecutorService 并提交这样的任务:future = scheduledExecutorService.schedule(myRunnableTask, delay, timeunit)然而,某个事件可能会在不确定的时间后发生,这表明不再需要此任务。所以我需要取消这个任务,我正在使用boolean cancelled = future.cancel(false)线。取消后,我必须根据提交的可运行文件是否实际运行来采取不同的操作。在这里,让我们首先进入 Oracle 文档并阅读cancelled标志的含义:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#cancel(boolean)返回:如果任务无法取消,则返回 false,通常是因为它已经正常完成;否则为真这就是关于返回值的全部内容。似乎写这个文本行的人不确定false这里的返回值,但我想我可以接受。现在让我们专注于案例,当它返回时true。这里有两种可能:该任务实际上已被取消并且 runnable 从未运行过。可运行对象正在运行,因此无法取消。(除非我做了一些线程中断逻辑,我真的不想这样做)我对这两种情况都没有意见,但我想知道实际发生了哪一种情况并采取相应的行动。如果runnable正在处理中,那么我可以接受它完成它的工作,我想等待它完成然后做一件事。但如果它被取消并且根本不会运行,我想做另一件事。你能推荐一种方法吗?我错过了什么吗?
查看完整描述

2 回答

?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

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

  • ASet<Runnable>跟踪Runnable线程池已开始执行的 s。

  • AMap<ScheduledFuture<?>, Runnable>将 a 映射ScheduledFuture<?>到其各自的Runnable.

    • 安排任务后,您应立即将ScheduledFuture及其各自添加RunnableMap.

    • 如果在调度任务本身的情况下以原子方式执行插入Map,那么您可以避免即使在取消之后也ScheduledFuture从未添加到的边缘情况。Map

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

覆盖此方法时,您可以RunnableSet<Runnable>.

然后,当 aScheduledFuture被取消时,您可以调用set.contains(map.get(future)),它会告诉您RunnableScheduledFuture映射到的)是否已执行。


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


查看完整回答
反对 回复 2022-11-02
?
千万里不及你

TA贡献1784条经验 获得超9个赞

我最终为这个问题写了这样的东西。源代码和一些单元测试可以在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);

        }

    }

}



查看完整回答
反对 回复 2022-11-02
  • 2 回答
  • 0 关注
  • 87 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号