首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >取消CompletableFuture链

取消CompletableFuture链
EN

Stack Overflow用户
提问于 2014-08-21 03:42:02
回答 1查看 6.1K关注 0票数 10

我有一个异步服务调用链,我想取消它。实际上,我有两个服务链并行进行,如果其中一个成功了,我想取消另一个。

对于番石榴的期货,我习惯于通过取消最后一个期货来取消整个期货链。看来我不能用java-8的未来来做这件事。,除非有人对方法有很好的了解。

如果您选择接受,就是告诉我是否可以保留我漂亮的语法并取消链式。否则,我将编写自己的链接,未来的包装-特别是在this question之后。

接下来是我自己的测试和尝试。

代码语言:javascript
复制
@Test
public void shouldCancelOtherFutures() {
    // guava
    ListenableFuture<String> as = Futures.immediateFuture("a");
    ListenableFuture<String> bs = Futures.transform(as, (AsyncFunction<String, String>) x -> SettableFuture.create());
    ListenableFuture<String> cs = Futures.transform(bs, (AsyncFunction<String, String>) x -> SettableFuture.create());
    ListenableFuture<String> ds = Futures.transform(cs, Functions.<String>identity());

    ds.cancel(false);
    assertTrue(cs.isDone()); // succeeds

    // jdk 8
    CompletableFuture<String> ac = CompletableFuture.completedFuture("a");
    CompletableFuture<String> bc = ac.thenCompose(x -> new CompletableFuture<>());
    CompletableFuture<String> cc = bc.thenCompose(x -> new CompletableFuture<>());
    CompletableFuture<String> dc = cc.thenApply(Function.identity());

    dc.cancel(false);
    assertTrue(cc.isDone()); // fails
}

(假设每个thenCompose()Futures.transform(x, AsyncFunction)代表一个异步服务调用。)

我明白为什么道格·李的研究生大军是这样做的。有了支链,一切都应该取消吗?

代码语言:javascript
复制
CompletableFuture<Z> top = new CompletableFuture<>()
    .thenApply(x -> y(x))
    .thenCompose(y -> z(y));

CompletableFuture<?> aBranch = top.thenCompose(z -> aa(z));
CompletableFuture<?> bBranch = top.thenCompose(z -> bb(z));

...
bBranch.cancel(false);
// should aBranch be canceled now?

我可以用一个自定义包装函数来解决这个问题,但是它扰乱了漂亮的语法。

代码语言:javascript
复制
private <T,U> CompletableFuture<U> transformAsync(CompletableFuture<T> source, Function<? super T,? extends CompletableFuture<U>> transform) {
    CompletableFuture<U> next = source.thenCompose(transform);
    next.whenComplete((x, err) -> next.cancel(false));
    return next;
}

private <T,U> CompletableFuture<U> transform(CompletableFuture<T> source, Function<T,U> transform) {
    CompletableFuture<U> next = source.thenApply(transform);
    next.whenComplete((x, err) -> next.cancel(false));
    return next;
}

// nice syntax I wished worked
CompletableFuture<?> f1 = serviceCall()
        .thenApply(w -> x(w))
        .thenCompose(x -> serviceCall())
        .thenCompose(y -> serviceCall())
        .thenApply(z -> $(z));

// what works, with less readable syntax
CompletableFuture<?> f2 =
        transform(
            transformAsync(
                transformAsync(
                    transform(serviceCall, x(w)),
                    x -> serviceCall()),
                y -> serviceCall()),
            z -> $(z));
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2014-08-21 11:08:20

这取决于你的目标是什么。我假设,让中间CompletableFuture报告一个完整的状态并不重要,因为在使用链式结构调用时通常不会注意到这一点。最重要的一点是,你希望你昂贵的serviceCall()不会被触发。

一种解决办法可以是:

代码语言:javascript
复制
CompletableFuture<String> flag=new CompletableFuture<>();

CompletableFuture<String> ac = serviceCall()
  .thenCompose(x -> flag.isCancelled()? flag: serviceCall())
  .thenCompose(x -> flag.isCancelled()? flag: serviceCall());
ac.whenComplete((v,t)->flag.cancel(false));// don’t chain this call

这将像在解决方案中一样使用whenComplete调用,但只在最终的CompletableFuture上将取消消息传播到专用的flag对象。调用cancel后,下一次thenCompose调用将检测取消并返回取消的未来,因此取消将传播该链,因此不会调用更多的组合或应用方法。

缺点是这不能与thenApply相结合,因为Function不能返回被取消的未来。因此,当异步服务调用完成并与Function链接时,即使发生取消,也将应用该函数。

解决此问题的另一种解决方案是为您的serviceCall创建一个包装器函数,其中包括启动前和完成后的测试:

代码语言:javascript
复制
CompletableFuture<String> serviceCall(CompletableFuture<String> f) {
    if(f.isCancelled()) return f;
    CompletableFuture<String> serviceCall=serviceCall();
    return serviceCall.thenCompose(x->f.isCancelled()? f: serviceCall);
}

然后您的用例将如下所示:

代码语言:javascript
复制
CompletableFuture<String> flag=new CompletableFuture<>();

CompletableFuture<String> ac = serviceCall(flag)
  .thenApply(w->x(w))
  .thenCompose(x -> serviceCall(flag))
  .thenCompose(x -> serviceCall(flag))
  .thenApply(z -> $(z));
ac.whenComplete((v,t)->flag.cancel(false));

当然,您必须将<String>替换为原始serviceCall()CompletableFuture<T>使用的任何类型参数。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25417881

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档