在Java的异步编程场景中,当多个异步任务存在先后依赖、结果传递或者并行组合的需求时,传统的Future接口只能通过阻塞获取结果,无法优雅实现链式回调。CompletableFuture弥补了这一缺陷,支持通过一系列回调方法编排异步任务,实现非阻塞的链式执行逻辑。

CompletableFuture基础创建方式
实现链式回调的第一步是创建CompletableFuture实例,常用的创建方式有两种,分别对应无返回值和有返回值的异步任务。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class CompletableFutureDemo {
// 自定义线程池,避免共用ForkJoinPool导致任务阻塞
private static final ExecutorService executor = Executors.newFixedThreadPool(5);
public static void main(String[] args) throws Exception {
// 方式1:创建无返回值的异步任务
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
System.out.println("执行无返回值异步任务,线程名:" + Thread.currentThread().getName());
}, executor);
// 方式2:创建有返回值的异步任务
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("执行有返回值异步任务,线程名:" + Thread.currentThread().getName());
return "初始结果";
}, executor);
}
}
串行链式回调实现
当后续任务依赖前一个异步任务的结果时,可以使用串行链式回调方法,常用的有thenApply、thenAccept、thenRun,三者分别对应有返回值转换、消费结果无返回值、不依赖结果执行任务三种场景。
thenApply:结果转换链式回调
thenApply接收前一个任务的结果,处理后返回新的结果,支持继续链式调用。
public static void serialChainDemo() throws Exception {
CompletableFuture<String> resultFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("第一个任务:查询用户ID");
return "1001";
}, executor).thenApply(userId -> {
System.out.println("第二个任务:根据用户ID查询用户名,用户ID:" + userId);
return "张三";
}).thenApply(userName -> {
System.out.println("第三个任务:拼接用户欢迎语,用户名:" + userName);
return "欢迎用户:" + userName;
});
// 获取最终链式执行结果
String finalResult = resultFuture.get();
System.out.println("最终链式结果:" + finalResult);
}
thenCompose:避免嵌套CompletableFuture
如果回调方法本身返回的是CompletableFuture,直接使用thenApply会得到嵌套的CompletableFuture结构,此时需要使用thenCompose展开嵌套,实现扁平化的链式调用。
public static void thenComposeDemo() throws Exception {
// 模拟查询用户信息的异步方法
CompletableFuture<String> queryUser(String userId) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询用户信息,用户ID:" + userId);
return "用户:" + userId;
}, executor);
}
// 模拟查询用户订单的异步方法
CompletableFuture<String> queryOrder(String userInfo) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询用户订单,用户信息:" + userInfo);
return "订单列表:" + userInfo;
}, executor);
}
// 使用thenCompose避免嵌套
CompletableFuture<String> finalResult = queryUser("1001")
.thenCompose(userInfo -> queryOrder(userInfo));
System.out.println("最终结果:" + finalResult.get());
}
并行组合链式回调
当多个异步任务没有依赖关系,需要等待所有任务完成后再处理后续逻辑时,可以使用thenCombine或者allOf实现并行组合回调。
thenCombine:两个任务结果组合
thenCombine可以等待两个独立的CompletableFuture都完成后,将两者的结果合并处理。
public static void thenCombineDemo() throws Exception {
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1:查询商品库存");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "库存:100";
}, executor);
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2:查询商品价格");
try {
Thread.sleep(1500);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "价格:299元";
}, executor);
// 组合两个任务的结果
CompletableFuture<String> combinedResult = task1.thenCombine(task2, (r1, r2) -> {
System.out.println("合并两个任务的结果");
return r1 + "," + r2;
});
System.out.println("组合结果:" + combinedResult.get());
}
allOf:多个任务等待全部完成
如果有超过两个的并行任务,需要等待全部完成后执行后续逻辑,可以使用allOf方法。
public static void allOfDemo() throws Exception {
CompletableFuture<String> task1 = CompletableFuture.supplyAsync(() -> "任务1完成", executor);
CompletableFuture<String> task2 = CompletableFuture.supplyAsync(() -> "任务2完成", executor);
CompletableFuture<String> task3 = CompletableFuture.supplyAsync(() -> "任务3完成", executor);
CompletableFuture<Void> allTasks = CompletableFuture.allOf(task1, task2, task3);
// 等待所有任务完成后再执行后续逻辑
allTasks.get();
System.out.println("所有并行任务都已完成");
// 可以分别获取各个任务的结果
System.out.println("任务1结果:" + task1.get());
System.out.println("任务2结果:" + task2.get());
System.out.println("任务3结果:" + task3.get());
}
链式回调中的异常处理
异步任务执行过程中可能出现异常,CompletableFuture提供了exceptionally、handle方法处理链式回调中的异常,避免异常导致后续链式逻辑中断。
public static void exceptionHandleDemo() throws Exception {
CompletableFuture<String> resultFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("执行可能出错的异步任务");
// 模拟异常
if (true) {
throw new RuntimeException("任务执行出现异常");
}
return "正常结果";
}, executor).exceptionally(ex -> {
// 异常发生时返回默认值
System.out.println("捕获到异常:" + ex.getMessage());
return "默认结果";
}).thenApply(r -> {
// 异常发生后仍会继续执行后续链式逻辑
System.out.println("处理异常后的结果:" + r);
return "最终:" + r;
});
System.out.println("最终结果:" + resultFuture.get());
}
注意事项
- 建议自定义线程池而不是使用默认的ForkJoinPool,避免耗时任务阻塞其他任务执行
- 链式回调中如果不调用
get、join方法,主线程不会等待异步任务执行完成 thenApply等方法默认和前一个任务使用同一个线程,如果需要指定线程池,可以使用带Executor参数的重载方法,比如thenApplyAsync- 使用
allOf时如果需要获取所有任务的结果,需要单独调用每个任务实例的get方法
CompletableFuture异步任务链式回调Java修改时间:2026-06-25 08:45:19