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

取消由执行者服务控制的ComppletableFuture

岳涵煦
2023-03-14

我有一个执行器服务,它将计算出的数据转发到可完成的未来

class DataRetriever {
    private final ExecutorService service = ...;

    public CompletableFuture<Data> retrieve() {
        final CompletableFuture<Data> future = new CompletableFuture<>();

        service.execute(() -> {
            final Data data = ... fetch data ...
            future.complete(data);
        });
        return future;
    }
}

我希望客户端/用户能够取消任务:

final DataRetriever retriever = new DataRetriever();
final CompletableFuture<Data> future = retriever().retrieve();

future.cancel(true);

这不起作用,因为这将取消外部的可完成未来,而不是executor服务中计划的内部未来。

是否有可能将外部未来的取消()传播到内部未来?

共有3个答案

郤飞英
2023-03-14

使用我的Tascalate并发库,您的代码可以重写如下:

class DataRetriever {
  private final ExecutorService service = ...;

  public Promise<Data> retrieve() {
    return CompletableTask.supplyAsync(() -> {
      final Data data = ... fetch data ...
      return data;
    }, service);
  }
}

PromiseCompletableTask,都是我的库中的类,您可以在我的博客中阅读更多内容

乔丁雨
2023-03-14
匿名用户

Pillar提到的另一个解决方案是扩展< code>CompletableFuture。这里有一个方法与您现有的代码非常相似。它还处理异常,这是一个不错的好处。

class CancelableFuture<T> extends CompletableFuture<T> {
    private Future<?> inner;

    /**
     * Creates a new CancelableFuture which will be completed by calling the
     * given {@link Callable} via the provided {@link ExecutorService}.
     */
    public CancelableFuture(Callable<T> task, ExecutorService executor) {
        this.inner = executor.submit(() -> complete(task));
    }

    /**
     * Completes this future by executing a {@link Callable}. If the call throws
     * an exception, the future will complete with that exception. Otherwise,
     * the future will complete with the value returned from the callable.
     */
    private void complete(Callable<T> callable) {
        try {
            T result = callable.call();
            complete(result);
        } catch (Exception e) {
            completeExceptionally(e);
        }
    }

    @Override
    public boolean cancel(boolean mayInterrupt) {
        return inner.cancel(mayInterrupt) && super.cancel(true);
    }
}

然后,在DataRetriever中,您只需执行以下操作:

public CompletableFuture<Data> retrieve() {
    return new CancelableFuture<>(() -> {... fetch data ...}, service);
}

左康安
2023-03-14

CompletableFuture#cancel实际上仅用于将CompletableFuture标记为已取消。它不会通知正在执行的任务停止,因为它与任何此类任务都没有关系。

javadoc 暗示了这一点

mayInterruptIfRunning - 此值在此实现中没有影响,因为中断不用于控制处理。

在你的示例中,内在的未来是一个未来,而不是一个CompletableFuture,它确实与执行Runnable(或Callable)有关系。在内部,由于它知道任务正在哪个线程上执行,因此它可以向它发送中断以尝试停止它。

一种选择是返回某种元组(例如一些POJO),该元组提供对您的CompletableFuture和由ExecutorService#提交返回的Future的引用。如果需要,您可以使用Future取消。您必须记住取消完成您的CompletableFuture,以便您的代码的其他部分不会永远保持阻塞/饥饿状态。

 类似资料:
  • 问题内容: 我想使用asyncio调用loop.run_in_executor在Executor中启动一个阻塞函数,然后在以后取消它,但这似乎对我不起作用。 这是代码: 我希望上面的代码仅允许阻塞函数输出: 然后查看非阻塞函数的输出。但是,即使我取消了,阻碍性的未来仍在继续。 可能吗?还有其他方法吗? 谢谢 问题答案: 在这种情况下,一旦它真正开始运行,就无法取消它,因为您依赖的行为,并且它的文档

  • 问题内容: 我一直在阅读文档并进行搜索,但似乎找不到直接的答案: 你可以取消已经执行的任务吗?(由于任务已开始,需要一段时间,因此需要取消一半) 我是从Celery FAQ的文档中找到的 但是我不清楚这是否会取消排队的任务,或者是否会杀死工作程序上正在运行的进程。感谢你能摆脱的光芒! 问题答案: 撤销将取消任务执行。如果任务被吊销,工人将忽略该任务并且不执行它。如果你不使用持久撤销,则可以在wor

  • 如果网络连接已打开超过几个小时,我将使用关闭网络连接。然而,在大多数情况下,网络连接在达到超时之前就关闭了,因此我取消了。在这种情况下,我还希望executor服务终止并释放其线程池。 令我惊讶的是,这并不是开箱即用的:虽然我在调度任务后对executor服务调用了<code>shutdown(),但当其唯一调度的任务被取消时,executor不会自动终止。从这种行为甚至可能是正确的,因为可以说取

  • 我有一个糟糕的服务人员,不再更新。我首先注意到了Chrome中的问题。然后,我将以下代码放入索引中。html文件和软件中的。js(服务工作者)文件。在大多数情况下,它似乎运行良好。Firefox似乎是唯一一个没有删除服务工作者的浏览器。我使用下面的文章创建了注销脚本。 如何卸载Service Worker? 我也用过这篇文章和代码,得到了同样的结果。 我如何删除一个有缺陷的服务人员,或者实现一个“

  • 我正试图实现一个轮询机制。我想根据一些条件增加或减少轮询间隔。我使用mono.repeat with delayElements来执行带有间隔的重复任务。但我无法根据一些条件找到修改延迟的方法。

  • Feign介绍 Feign是一个声明式的web service客户端,它使得编写web service客户端更为容易。创建接口,为接口添加注解,即可使用Feign。Feign可以使用Feign注解或者JAX-RS注解,还支持热插拔的编码器和解码器。Spring Cloud为Feign添加了Spring MVC的注解支持,并整合了Ribbon和Eureka来为使用Feign时提供负载均衡。 译自:h