CompletableFuture执行顺序异常:completeOnTimeout先于runAsync执行
问题:CompletableFuture的completeOnTimeout为何提前执行?
我使用Oracle Java 17编写了如下代码:
package com.test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class Solution { public void startCompletableFutureExample() { CompletableFuture.runAsync(() -> { System.out.println("async operation"); }) .completeOnTimeout( timeout(), 10000, TimeUnit.MILLISECONDS); } private Void timeout() { System.out.println("timeout happens"); return null; } }
调用startCompletableFutureExample()方法时,输出为:
timeout happens async operation
而我预期仅输出“async operation”(因为远未达到10秒超时时间)。为何completeOnTimeout会先于runAsync执行?我是否操作有误?
原因分析与解决方案
你犯了一个常见的参数传递错误:在调用completeOnTimeout时,直接执行了timeout()方法,而不是传递一个延迟执行的逻辑。
completeOnTimeout的第一个参数如果是具体值类型,Java会在构建方法链的主线程中立即执行timeout()来获取参数值,这就导致timeout()在异步任务启动前就被调用,和超时逻辑完全无关。
正确的做法是使用completeOnTimeout的Supplier重载方法,传递一个Lambda表达式作为延迟执行的逻辑,这样只有当超时事件真的发生时,才会调用timeout()方法。
修正后的代码如下:
package com.test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; public class Solution { public void startCompletableFutureExample() { CompletableFuture.runAsync(() -> { System.out.println("async operation"); }) // 传递Supplier,仅超时触发时执行 .completeOnTimeout( () -> timeout(), 10000, TimeUnit.MILLISECONDS); } private Void timeout() { System.out.println("timeout happens"); return null; } }
修改后,当异步任务在10秒内完成时,只会输出async operation;只有当任务超时未完成时,才会执行timeout()并输出timeout happens。
内容的提问来源于stack exchange,提问作者Eugene Zimin
相关产品推荐
相关产品推荐

