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

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

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似乎可以解决问题。有人可以解释一下为什么吗?还是这是我的代码中的某个错误,并且不应以这种方式运行?

最佳答案

thenApply[Async]接受评估为任意值的函数。返回值后,将来将使用该值来完成。当函数(如您的代码中)返回另一个future时,这并没有增加其他含义,future将是结果值(无论是否完成),就像其他任何对象一样。

实际上,您的

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()
            );
        }
    );
}

09-11 08:04
查看更多