需要说明,applyAsync和嵌套的allOf将CompletionStage视为已完成

问题描述 投票:0回答:1

在我的应用程序中,我有3个未来的调用,这是并行完成的,当收到其中一个的响应时,我还有另外3个请求,所有这些都应该在继续执行代码之前完成,正好是来自spring的DeferredResult

过了一会儿,我意识到页面有时会在后3个请求完成之前呈现。原始源代码(为简单起见,省略逻辑):

public DeferredResult<String> someControllerMethod() {

    DeferredResult<String> result = new DeferredResult();

    CompletableFuture.allOf(
        future1(),
        future2(),
        future3()
    )
    .whenComplete((aVoid, throwable) -> result.setResult("something"));

    return result;
}

public CompletableFuture<?> future3() {
    return someService.asyncCall()
        .thenApplyAsync(response -> {
            ....
            return CompletableFuture.allOf(
                future4(),
                future5(),
                future6()
            );
        }
    );
}

随着thenApplyAsync有时DeferredResult在实际未来之前完成,而改为thenComposeAsync似乎解决了这个问题。有人能解释我为什么吗?或者它是我的代码中的一个错误,它应该不这样做?

java java-8 completable-future
1个回答
2
投票

thenApply[Async]接受一个求值为任意值的函数。返回值后,将使用该值完成将来的操作。当函数(如在代码中)返回另一个未来时,这不会为其添加额外的含义,将来将是结果值,无论是否已完成,就像任何其他对象一样。

事实上,你的

public CompletableFuture<Void> future3() {
    return someService.asyncCall()
        .thenApplyAsync(response -> {
            ....
            return CompletableFuture.allOf(
                future4(),
                future5(),
                future6()
            );
        }
    );
}

方法甚至没有编译,因为结果是CompletableFuture<CompletableFuture<Void>>,一个未来的结果值是另一个未来。唯一不发现错误的方法是使用更广泛的类型,例如CompletableFuture<Object>CompletableFuture<?>,作为future3()的返回类型。

相比之下,thenCompose[Async]期望一个能够评估另一个未来的函数,达到您期望的结果。这是“应用”和“撰写”之间的根本区别。如果你为CompletableFuture<Void>保留特定的future3()返回类型,编译器已经引导你使用“compose”,因为只有那将被接受。

public CompletableFuture<Void> future3() {
    return someService.asyncCall()
        .thenComposeAsync(response -> {
            ....
            return CompletableFuture.allOf(
                future4(),
                future5(),
                future6()
            );
        }
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.