在我的应用程序中,我有3个未来的调用,它们是并行完成的,当收到其中一个的响应时,我还有另外3个请求,所有这些都应该在继续执行代码之前完成,正是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
似乎可以解决问题。有人能解释我为什么吗?或者它是我的代码中的一个错误,它应该不这样做?
答案 0 :(得分: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()
返回类型,编译器已经指导您使用“撰写”,因为只有这将被接受。
public CompletableFuture<Void> future3() {
return someService.asyncCall()
.thenComposeAsync(response -> {
....
return CompletableFuture.allOf(
future4(),
future5(),
future6()
);
}
);
}