递归取消allOf CompletableFuture [英] Recursively cancel an allOf CompletableFuture

查看:123
本文介绍了递归取消allOf CompletableFuture的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有

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

当我执行many.cancel()时会发生什么? future1future2也将被取消吗?如果没有,实现这一目标的最干净的方法是什么?我不愿意保留future1future2,只是想在想取消many时可以取消它们.

what will happen when I do many.cancel()? Will future1 and future2 be cancelled as well? If not, what would be the cleanest way to achieve this? I'm reluctant to hold on to future1 and future2, just to be able to cancel them when I want to cancel many.

我为什么要这么做的一些背景:当接收到一条数据时,我需要请求匹配的(可能是将来的数据)来执行计算.如果有新的数据到达,我想取消较早计算的完成,因为结果将立即被新计算取代.

Some background on why I want this: when receiving a piece of data, I need to request matching, potentially future data to perform a computation. If a newer piece of data arrives, I want to cancel the completion of the earlier computation, because the result will immediately be superceded by the new computation.

推荐答案

在使生活变得不必要之前,您应该了解取消CompletableFuture的实际作用.最重要的是,它不会停止相关的计算.

Before you make you life harder than necessary, you should become aware of what cancelling a CompletableFuture actually does. Most important, it does not stop the associated computation.

如果与CompletableFuture相关的计算已在运行,但尚未完成,取消CompletableFuture会将其转换为已取消"状态,这可能对所有相关阶段产生直接影响,但不会立即生效.计算将一直持续到完成,尽管尝试完成已取消的将来不会有任何效果.

If a computation associated with a CompletableFuture is already running, but has not completed yet, cancelling a CompletableFuture turns it into the "cancelled" state, which may have an immediate effect on all dependent stages, but not on the computation, which will continue until complete, though its attempt to complete the cancelled future will not have any effect.

尽管其他Future可能会被中断取消,这将停止计算,但是如果它检查中断,则不适用于CompletableFuture,请参见

While other Future’s might be cancelled with interruption, which will stop the computation, if it checks for interruption, this doesn’t apply to CompletableFuture, see CompletableFuture.cancel(boolean):

参数:

mayInterruptIfRunning-此值在此实现中无效,因为不使用中断来控制处理.

Parameters:

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

因此,成功取消future1future2时,唯一的直接效果就是取消many,也可以通过在many本身上调用cancel来实现.如果存在更多的依存阶段,它将产生更广泛的影响,但是由于您已声明不想保留对future1future2的引用,因此似乎并非如此.

So when you cancel either, future1 or future2, successfully, the only immediate effect would be the cancellation of many, which you can also achieve by calling cancel on many itself. It would have a broader effect, if there were more dependent stages, but since you stated, that you don’t want to keep references to future1 or future2, this doesn’t seem to be the case.

下面的代码演示了该行为:

The following code demonstrates the behavior:

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)还是通过truefalse;它不会停止正在进行的Supplier评估.

regardless of whether you call supply.cancel(true) or then.cancel(true) or whether you pass true or false; it won’t stop the ongoing Supplier evaluation.

如果尚未开始关联的计算,并且确实会在启动时检查取消状态,就像CompletableFuture中的便捷方法产生的动作那样,就会有所不同.这是一种罕见的情况,通常,您的service.request(paramN)调用应该触发评估.

There will be a difference, if the associated computation hasn’t been started yet and it does check the cancellation state when starting, like with the actions produced by the convenience methods in CompletableFuture. This is a rare situation, as normally, your service.request(paramN) call is supposed to trigger the evaluation.

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

It’s a fundamental property of the CompletableFuture, as its name suggests, that it is completable, i.e. anyone could call complete on it, thus, the CompletableFuture can’t control whoever might eventually call complete on it in the future. So all, cancel can achieve, is to set it to the cancelled state, which implies ignoring subsequent completion attempts and propagating the cancellation downward to the dependent actions.

因此,最重要的是,只需在many实例上调用cancel可能已经很好,因为在future1future2上调用cancel不太可能产生值得代码的复杂性.

So the bottom line is that you might already be fine with just calling cancel on the many instance, because calling cancel on future1 and future2 is unlikely to have an effect that is worth the complication of your code.

这篇关于递归取消allOf CompletableFuture的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆