如果我有
CompletableFuture<Something> future1 = service.request(param1);
CompletableFuture<Something> future2 = service.request(param2);
CompletableFuture<Void> many = CompletableFuture.allOf(future1, future2);
当我执行 many.cancel()
时会发生什么? future1
和 future2
也会取消吗?如果没有,实现这一目标的最干净的方法是什么?我不愿意坚持 future1
和 future2
,只是为了能够在我想取消 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.
因此,当您成功取消 future1
或 future2
时,唯一的直接影响是取消 many
,您可以也可以通过在 many
本身上调用 cancel
来实现。如果有更多的依赖阶段,它会产生更广泛的影响,但既然你说过,你不想保留对 future1
或 future2
的引用,这不会似乎不是这样。
以下代码演示了该行为:
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/