CompletableFuture allOf的whenComplete是否保证最后执行?
CompletableFuture.allOf的whenComplete是否能保证最后执行?
是否能保证CompletableFuture.allOf对应的whenComplete方法最后执行?我在思考当最后一个Future完成时,它自身的whenComplete可能会非确定性地晚于allOf的whenComplete被调用。例如是否可能出现如下输出:
A
Combined
B?
先修正你提供的代码(原代码存在未定义变量的语法错误),可运行版本如下:
public class CompletableFutureDemo { public static void main(String[] args) { CompletableFuture<String> aFuture = new CompletableFuture<>(); CompletableFuture<String> bFuture = new CompletableFuture<>(); CompletableFuture<String> cFuture = CompletableFuture.completedFuture("C"); aFuture.whenComplete((s, e) -> System.out.println(s)); bFuture.whenComplete((s, e) -> System.out.println(s)); CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(aFuture, bFuture, cFuture); combinedFuture.whenComplete((v, e) -> System.out.println("Combined")); aFuture.complete("A"); bFuture.complete("B"); } }
核心结论:不能保证allOf的whenComplete一定在所有子Future的回调之后执行,确实可能出现你描述的输出顺序。
原因解析:
- CompletableFuture的回调执行依赖线程调度:默认情况下,回调任务会被提交到
ForkJoinPool.commonPool()线程池,或者在调用complete()的线程同步执行(如果当前线程允许的话)。 - 当最后一个子Future完成时,会同时触发两个独立的调度逻辑:
- 该子Future自身的
whenComplete回调任务进入调度队列 allOf对应的Future完成,它的whenComplete回调任务也进入调度队列
- 该子Future自身的
- 这两个任务的执行顺序由线程池的调度策略决定,没有严格的先后保证,完全可能出现
allOf的回调先执行、最后一个子Future的回调后执行的情况。
验证说明:
多次运行上述代码,大概率会看到A、B、Combined的顺序,但偶尔也会出现A、Combined、B或者B、Combined、A的情况,顺序完全取决于线程池的调度时机。
如何保证allOf回调最后执行?
如果需要确保Combined一定在所有子回调之后输出,可以把每个子Future的回调也封装成CompletableFuture,再将这些新Future传入allOf,示例如下:
public class CompletableFutureDemo { public static void main(String[] args) { CompletableFuture<String> aFuture = new CompletableFuture<>(); CompletableFuture<String> bFuture = new CompletableFuture<>(); CompletableFuture<String> cFuture = CompletableFuture.completedFuture("C"); // 将子回调封装为新的CompletableFuture CompletableFuture<Void> aCallback = aFuture.whenComplete((s, e) -> System.out.println(s)); CompletableFuture<Void> bCallback = bFuture.whenComplete((s, e) -> System.out.println(s)); // allOf等待子Future完成+它们的回调执行完毕 CompletableFuture<Void> combinedFuture = CompletableFuture.allOf(aCallback, bCallback, cFuture); combinedFuture.whenComplete((v, e) -> System.out.println("Combined")); aFuture.complete("A"); bFuture.complete("B"); } }
内容的提问来源于stack exchange,提问作者Howard Fring
相关产品推荐
相关产品推荐

