CompletableFuture<Something> future1 = service.request(param1); CompletableFuture<Something> future2 = service.request(param2); CompletableFuture<Void> many = CompletableFuture.allOf(future1,future2);
当我做many.cancel()时会发生什么? future1和future2也会被取消吗?如果没有,最简单的方法是什么?我不愿意坚持未来1和未来2,只是为了能够在取消许多时取消它们.
关于我为什么要这样做的一些背景:当接收一条数据时,我需要请求匹配的,可能未来的数据来执行计算.如果有更新的数据到达,我想取消先前计算的完成,因为结果将立即被新计算取代.
解决方法
如果与CompletableFuture相关联的计算已经运行但尚未完成,则取消CompletableFuture会将其转换为“已取消”状态,这可能对所有相关阶段产生直接影响,但不会影响计算,这将持续到完成,虽然它试图完成取消的未来将不会有任何影响.
虽然其他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时,唯一的直接影响是取消许多,您也可以通过调用许多本身取消来实现.如果有更多的依赖阶段会产生更广泛的影响,但是既然你说过,你不想保留对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或false;它不会阻止正在进行的供应商评估.
如果相关计算尚未开始并且它在启动时检查取消状态,则会有所不同,就像CompletableFuture中的便捷方法所产生的操作一样.这是一种罕见的情况,通常,您的service.request(paramN)调用应该触发评估.
正如其名称所示,它是CompletableFuture的一个基本属性,它是可完成的,即任何人都可以在其上调用complete,因此,CompletableFuture无法控制将来可能最终调用完成的任何人.因此,取消可以实现的是将其设置为取消状态,这意味着忽略后续完成尝试并将取消向下传播到依赖操作.
所以最重要的是你可能已经很好,只需在很多实例上调用cancel,因为在future1和future2上调用cancel不太可能产生值得代码复杂化的效果.