递归取消allOff CompletableFuture
如果我有
CompletableFuture future1 = service.request(param1); CompletableFuture future2 = service.request(param2); CompletableFuture many = CompletableFuture.allOf(future1, future2);
当我做many.cancel()
时会发生什么? future1
和future2
被取消吗? 如果没有,那么实现这一目标的最简洁方法是什么? 我不愿意坚持future1
和future2
,只是为了能够在取消many
时取消它们。
关于为什么我想要这个的一些背景:当接收一条数据时,我需要请求匹配的,可能未来的数据来执行计算。 如果有更新的数据到达,我想取消先前计算的完成,因为结果将立即被新计算取代。
在你让生活变得艰难之前,你应该知道取消CompletableFuture
实际上做了什么。 最重要的是,它不会停止相关的计算。
如果与CompletableFuture
相关联的计算已经运行但尚未完成,则取消CompletableFuture
会将其转换为“已取消”状态,这可能对所有相关阶段产生直接影响,但不会影响计算,这将持续到完成,虽然它试图完成取消的未来将不会有任何影响。
虽然其他Future
可能会被中断取消,这将停止计算,如果它检查中断,这不适用于CompletableFuture
,请参阅CompletableFuture.cancel(boolean)
:
参数:
mayInterruptIfRunning – 此值在此实现中无效,因为中断不用于控制处理。
因此,当您成功取消future1
或future2
,唯一的直接影响是取消many
,您也可以通过调用many
本身cancel
来实现。 如果有更多的依赖阶段会产生更广泛的影响,但是既然你说过,你不想继续引用future1
或future2
,那么情况似乎并非如此。
以下代码演示了该行为:
CompletableFuture supply = CompletableFuture.supplyAsync(() -> { LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2)); System.out.println("supplying value"); return "foo"; }); CompletableFuture 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
或false
; 它不会阻止正在进行的Supplier
评估。
如果相关计算尚未开始并且它在启动时检查取消状态,则会有所不同,就像CompletableFuture
的便捷方法所产生的操作一样。 这是一种罕见的情况,通常,您的service.request(paramN)
调用应该触发评估。
正如其名称所示,它是CompletableFuture
的基本属性,它是可complete
,即任何人都可以在其上调用complete
,因此, CompletableFuture
无法控制将来可能最终调用complete
的人。 因此, cancel
可以实现的是将其设置为取消状态,这意味着忽略后续完成尝试并将取消向下传播到依赖操作。
所以最重要的是你可能已经很好,只需在many
实例上调用cancel
,因为在future1
和future2
上调用cancel
不太可能产生值得代码复杂化的效果。
由CompletableFuture.allOf
构造的树不包含对CompletableFuture
的给定实例的任何引用。 相反,如果只是构建完成树,这是在所有给定的CompletableFutures完成时完成的 (来自JavaDocs )。
因此,您可能必须保留对所有CompletableFuture
引用,以便在需要时按顺序取消它们。
您可以尝试我的库: https : //github.com/vsilaev/tascalate-concurrent
它提供了真正可取消的CompletionStage实现(CompletableTask)以及组合它们的方法(Promises.all)
CompletionStage future1 = CompletableTask .complete(param1, myExecutor).thenApplyAsync(this::serviceCall); CompletionStage future2 = CompletableTask .complete(param2, myExecutor).thenApplyAsync(this::serviceCall); Promise> many = Promises.all(future1, future2);
现在你可以调用many.cancel(true)
, future1
和future2
都将被取消(如果还没有完成)。 此外,如果个别期货中的任何一个exception完成,则另一个将自动取消(再次,如果尚未完成)。