CompletableFuture 是 Java 8 引入的一个强大工具,用于处理异步编程和非阻塞操作。它实现了 Future 接口,并提供了丰富的方法来组合、转换和处理异步任务的结果。以下是对 CompletableFuture 的详细介绍:
1. 基本概念
异步计算:CompletableFuture 可以在后台线程中执行任务,主线程无需等待结果。
回调机制:通过回调函数处理结果,避免阻塞。
组合操作:可以将多个异步任务组合成一个链式操作。
2. 创建 CompletableFuture
2.1 无返回值的异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 异步执行的任务(无返回值)
System.out.println("任务执行中...");
});
2.2 有返回值的异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 异步执行的任务(有返回值)
return "任务结果";
});
2.3 指定线程池
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
return "自定义线程池执行";
}, executor);
3. 获取结果
3.1 阻塞获取
String result = future.get(); // 阻塞当前线程直到任务完成
3.2 带超时的阻塞获取
String result = future.get(1, TimeUnit.SECONDS); // 超时则抛出异常
3.3 非阻塞获取(回调)
future.thenAccept(result -> {
// 任务完成后执行的操作
System.out.println("结果: " + result);
});
4. 处理结果
4.1 转换结果(thenApply)
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> "10")
.thenApply(Integer::parseInt) // 将 String 转换为 Integer
.thenApply(num -> num * 2); // 进一步处理结果
4.2 消费结果(thenAccept)
future.thenAccept(result -> {
System.out.println("处理结果: " + result);
});
4.3 无返回值的后续操作(thenRun)
future.thenRun(() -> {
System.out.println("任务完成,无需结果");
});
5. 组合多个 CompletableFuture
5.1 串行执行(thenCompose)
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenCompose(s ->
CompletableFuture.supplyAsync(() -> s + " World")
); // 结果: "Hello World"
5.2 并行执行后合并结果(thenCombine)
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 2);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 3);
CompletableFuture<Integer> result = future1.thenCombine(future2, (a, b) -> a * b); // 结果: 6
5.3 任意一个完成即继续(acceptEither)
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return "结果1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
Thread.sleep(500);
return "结果2";
});
future1.acceptEither(future2, result -> {
System.out.println("先完成的结果: " + result); // 输出: "结果2"
});
5.4 所有任务完成后继续(allOf)
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
allFutures.thenRun(() -> {
System.out.println("所有任务已完成");
});
6. 异常处理
6.1 捕获异常(exceptionally)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("模拟异常");
}).exceptionally(ex -> {
System.out.println("处理异常: " + ex.getMessage());
return "默认值"; // 异常时返回的默认值
});
6.2 更灵活的异常处理(handle)
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "结果")
.handle((result, ex) -> {
if (ex != null) {
return "处理异常: " + ex.getMessage();
} else {
return "正常结果: " + result;
}
});
7. 超时处理
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "结果";
}).orTimeout(1, TimeUnit.SECONDS); // 超时则抛出 TimeoutException
8. 实际应用场景
8.1 并行调用多个服务
CompletableFuture<String> service1 = CompletableFuture.supplyAsync(() -> callService1());
CompletableFuture<String> service2 = CompletableFuture.supplyAsync(() -> callService2());
CompletableFuture<String> service3 = CompletableFuture.supplyAsync(() -> callService3());
CompletableFuture<Void> allServices = CompletableFuture.allOf(service1, service2, service3);
CompletableFuture<List<String>> combined = allServices.thenApply(v ->
Arrays.asList(service1.join(), service2.join(), service3.join())
);
8.2 异步查询数据库
CompletableFuture<List<User>> future = CompletableFuture.supplyAsync(() ->
jdbcTemplate.query("SELECT * FROM users", userRowMapper)
);
future.thenAccept(users -> {
// 处理查询结果
});
9. 注意事项
线程池配置:默认使用 ForkJoinPool.commonPool(),建议根据业务场景自定义线程池。
避免阻塞:尽量使用非阻塞方法(如 thenApply、thenAccept)。
异常处理:始终处理可能的异常,避免任务无声失败。
总结
CompletableFuture 提供了强大的异步编程能力,通过链式调用和回调机制,可以优雅地处理复杂的异步场景。掌握它的关键在于理解以下方法:
创建:runAsync、supplyAsync
转换:thenApply、thenCompose
组合:thenCombine、allOf、anyOf
异常处理:exceptionally、handle
超时控制:orTimeout、completeOnTimeout
//这行代码的核心目的是:让主线程等待一组异步任务全部完成后再继续执行。
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();