java - 递归取消 allOf CompletableFuture

标签 java java-8 completable-future

如果我有

CompletableFuture<Something> future1 = service.request(param1);
CompletableFuture<Something> future2 = service.request(param2);
CompletableFuture<Void> many = CompletableFuture.allOf(future1, future2);

当我执行 many.cancel() 时会发生什么? future1future2 也会取消吗?如果没有,实现这一目标的最干净的方法是什么?我不愿意坚持 future1future2,只是为了能够在我想取消 many 时取消它们。

关于我为什么想要这个的一些背景:当接收到一段数据时,我需要请求匹配,可能是 future 的数据来执行计算。如果有较新的数据到达,我想取消先前计算的完成,因为结果将立即被新的计算所取代。

最佳答案

在让自己的生活比必要的更艰难之前,您应该了解取消 CompletableFuture 的实际作用。最重要的是,它不会停止相关的计算。

如果与 CompletableFuture 关联的计算已经在运行,但尚未完成,则取消 CompletableFuture 会将其转换为“已取消”状态,这可能有一个对所有相关阶段立即产生影响,但不会对计算产生影响,计算将一直持续到完成,尽管它试图完成已取消的 future 不会产生任何影响。

虽然其他 Future 可能会因中断而取消,这将停止计算,如果它检查中断,这不适用于 CompletableFuture,请参见 CompletableFuture.cancel(boolean) :

Parameters:

mayInterruptIfRunning - this value has no effect in this implementation because interrupts are not used to control processing.

因此,当您成功取消 future1future2 时,唯一的直接影响是取消 many,您可以也可以通过在 many 本身上调用 cancel 来实现。如果有更多的依赖阶段,它会产生更广泛的影响,但既然你说过,你不想保留对 future1future2 的引用,这不会似乎不是这样。

以下代码演示了该行为:

CompletableFuture<String> supply = CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    System.out.println("supplying value");
    return "foo";
});
CompletableFuture<String> then = supply.thenApply(s -> {
    System.out.println("Evaluating next stage");
    return s;
});
CompletableFuture<?> last = then.handle((s,t) -> {
    System.out.println("last stage: value: "+s+", throwable: "+t);
    return "";
});
System.out.println("cancelling: "+supply.cancel(true));
ForkJoinPool.commonPool().awaitQuiescence(1, TimeUnit.DAYS);

此代码可重现打印:

last stage: value: null, throwable: java.util.concurrent.CompletionException: java.util.concurrent.CancellationException
canceling: true
supplying value

(顺序可能会改变)

无论您是调用 supply.cancel(true) 还是 then.cancel(true) 还是传递 true;它不会停止正在进行的供应商评估。

如果关联的计算还没有开始,它会在开始时检查取消状态,就像 CompletableFuture 中的便捷方法产生的 Action 一样,会有区别。这是一种罕见的情况,通常情况下,您的 service.request(paramN) 调用应该会触发评估。

这是 CompletableFuture 的一个基本属性,顾名思义,它是可完成的,即任何人都可以调用 complete,因此,CompletableFuture 无法控制将来可能最终对其调用 complete 的人。因此,cancel 所能实现的就是将其设置为已取消状态,这意味着忽略后续完成尝试并将取消向下传播到相关操作。


所以最重要的是,您可能已经可以在 many 实例上调用 cancel 了,因为在 上调用 cancel >future1future2 不太可能产生值得您的代码复杂化的效果。

关于java - 递归取消 allOf CompletableFuture,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43389894/

相关文章:

java - DrJava:无法使用 JDK8.0 运行代码

java - CompletableFuture 超时后返回所有完成的结果

java - 如果他的列表满足条件,如何使用 Collection remove?

java - 如何在 java 8 lambda 表达式中获取方法参数名称?

java - 对可变数量的对象使用 CompletableFuture.allOf

java - 线程与 CompletableFuture

java - 使用接口(interface)从 Activity 到 Fragment 进行通信

java - 在 EclipseLink-2.5.2 中为可嵌入类配置 ID 类型时出现奇怪问题

java - Apache Jax-RS 破坏了 spring-integration-mail

java - 排除小括号字母上的标记