文章目录
1 Future和CompletableFuture的区别是什么?
1.1 功能范围差异
-
Future
仅提供基础异步任务状态查询(isDone/isCancelled)和结果获取(get()方法),无法实现任务链式调用或组合,需手动处理阻塞逻辑。 -
CompletableFuture
支持链式调用、组合任务(如thenApply、thenCombine等)和函数式编程,内置异常处理(exceptionally方法)与超时控制,可构建复杂异步流程。
1.2 阻塞与非阻塞特性
-
Future
必须通过阻塞式get()方法等待结果返回,易造成线程资源浪费。 -
CompletableFuture
提供join()非阻塞等待方法,支持回调机制(如whenComplete)自动触发后续操作,减少线程空转。
1.3 线程管理机制
-
Future
依赖外部ExecutorService提交任务,需手动管理线程池资源。 -
CompletableFuture
默认使用ForkJoinPool.commonPool(),支持自定义线程池,通过CAS无锁机制实现高效并发
1.4 异常处理方式
-
Future
任务异常仅在调用get()时抛出ExecutionException,需手动捕获处理。 -
CompletableFuture
通过exceptionally()方法捕获异常并返回默认值,支持异常传播到后续链式操作。
1.5 任务组合能力对比
-
Future
多个任务需通过循环或手动协调实现组合,代码复杂度高。 -
CompletableFuture
内置allOf/anyOf等多任务协调方法,支持结果聚合与依赖编排,实现"异步流水线处理。
1.6 总结
Future是基础异步模型,适合单一任务场景;CompletableFuture通过组合式编程和函数式特性,成为现代Java高并发编程的核心工具。
2 CompletableFuture详解
2.1 CompletableFuture 基础
什么是 CompletableFuture?
- 定义:Java 8 引入的异步编程工具,支持非阻塞、链式调用和任务组合。
- 特点:
- 基于 Future 的扩展,提供更丰富的异步操作。
- 支持函数式编程(如 Lambda 表达式)。
- 可手动完成任务或设置异常。
核心方法分类
方法类型 | 示例方法(有返回值/无返回值) | 用途 |
---|---|---|
任务创建 | supplyAsync/runAsync | 启动异步任务 |
链式处理 | thenApply/thenAccept | 对结果进行转换或消费 |
任务组合 | thenCompose/thenCombine | 组合多个 CompletableFuture |
异常处理 | exceptionally/handle | 处理异步任务中的异常 |
手动控制 | complete/completeExceptionally | 主动设置任务结果或异常 |
批量任务 | allOf/anyOf | 等待多个任务完成 |
2.2 核心方法详解
2.2.1 创建/获取结果和出发计算
创建
supplyAsync
- 用途:提交有返回值的异步任务。
- 参数:
Supplier<U>
: 提供结果的函数。Executor
(可选):自定义线程池(默认使用ForkJoinPool
(守护线程、分治理念))。
- 示例:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
return "Result";
});
runAsync
- 用途:提交无返回值的异步任务(Runnable)。
- 参数:
Runnable
: 无返回值的任务。Executor
(可选):自定义线程池。
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("Task executed");
});
获取结果出发计算
public T get() // 死等
public T get(Long timeout, TimeUnit unit) // 超时抛出异常
public T join() // 不需要抛出异常
public T getNow(T valueIfAbsent) //如果没有计算完结果,则给默认值(立即获取结果不阻塞)
public boolean complete(T value) // 如果计算完成返回True,否则返回False
2.2.2 对结果进行处理/消费
thenApply
handle
和thenApply
类似,
-
thenApply
遇到异常直接中断,不执行回调,会中断。 -
handle
可同时处理正常结果和异常,继续执行后续逻辑,不会中断。 -
用途:对结果进行转换(类似
Stream.map
)。任务A
执行完执行B
,B
需要A
的结果,同时任务B
有返回值。 -
参数:
Function<T, U>
,接受输入T
,返回U
。 -
示例
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> "10")
.thenApply(s -> Integer.parseInt(s)); // 转换为整数
thenAccept
- 用途:消费结果(不返回新值)。任务
A
执行完执行B
,B
需要A
的结果,但是任务B
无返回值。 - 参数:
Consumer<T>
,接受输入T
,无返回值。 - 示例
CompletableFuture.supplyAsync(() -> "Result")
.thenAccept(s -> System.out.println("Received: " + s));
thenRun
- 用途:在任务完成后执行操作(不访问结果)。任务
A
执行完执行B
,并且B
不需要A
的结果。 - 参数:Runnable。
- 示例:
CompletableFuture.supplyAsync(() -> "Result")
.thenRun(() -> System.out.println("Task finished"));
2.2.3 组合多个任务
thenCompose
- 用途:将两个异步任务串联(前一个结果作为后一个任务的输入)。
- 参数:
Function<T, CompletableFuture<U>>
。 - 示例:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> "10")
.thenCompose(s -> CompletableFuture.supplyAsync(() -> Integer.parseInt(s)));
thenCombine
- 用途:合并两个独立任务的结果。
- 参数:
CompletionStage<U>
:另一个任务。
BiFunction<T, U, V>
:合并函数。 - 示例
CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20);
futureA.thenCombine(futureB, (a, b) -> a + b)
.thenAccept(sum -> System.out.println("Sum: " + sum)); // 输出 30
allOf 和 anyOf
allOf
:等待所有任务完成。
CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20);
CompletableFuture<Void> all = CompletableFuture.allOf(futureA, futureB);
all.thenRun(() -> System.out.println("All tasks done"));
List<Object> list = Stream.of(futureA, futureB, futureC) // 获取所有的结果
.map(CompletableFuture::join) // 直接获取结果,不抛受检异常,不会阻塞,因为 allOf 已确保完成
.collect(Collectors.toList());
anyOf
:等待任一任务完成。
CompletableFuture<Object> any = CompletableFuture.anyOf(futureA, futureB);
any.thenAccept(result -> System.out.println("First result: " + result));
2.2.4 异常处理
exceptionally
- 用途:捕获异常并提供默认值。
- 参数:
Function<Throwable, T>
,返回降级结果。 - 示例:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
if (error) throw new RuntimeException("Error");
return 10;
}).exceptionally(ex -> {
System.out.println("Error: " + ex.getMessage());
return 0; // 返回默认值
});
handle
- 用途:无论成功或失败,统一处理结果和异常。
- 参数:
BiFunction<T, Throwable, U>
。 - 示例:
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 10)
.handle((result, ex) -> {
if (ex != null) return 0;
return result * 2;
});
2.2.5 手动控制任务
complete
- 用途:手动设置任务结果(如果未完成)。
CompletableFuture<String> future = new CompletableFuture<>();
future.complete("Manual Result"); // 立即完成
completeExceptionally
- 用途:手动设置任务异常。
future.completeExceptionally(new RuntimeException("Failed"));
3 高级操作(Java 9+)
orTimeout
- 用途:设置任务超时时间,超时抛出
TimeoutException
。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
Thread.sleep(2000);
return "Result";
}).orTimeout(1, TimeUnit.SECONDS); // 1秒超时
completeOnTimeout
- 用途:超时后提供默认值。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
Thread.sleep(2000);
return "Result";
}).completeOnTimeout("Timeout", 1, TimeUnit.SECONDS);
4 最佳实践
- 避免阻塞 get():尽量使用回调(如 thenAccept)替代 get()。
- 合理使用线程池
// 自定义线程池(避免耗尽默认线程池资源)
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletableFuture.supplyAsync(() -> task(), executor);
- 避免回调地狱:通过链式调用拆分复杂逻辑。
- 处理异常:始终使用
exceptionally
或handle
处理可能的异常。
5 完整示例
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
// 创建异步任务
CompletableFuture<Integer> futureA = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> futureB = CompletableFuture.supplyAsync(() -> 20);
// 合并结果并处理异常
CompletableFuture<Integer> combined = futureA.thenCombine(futureB, (a, b) -> a + b)
.exceptionally(ex -> {
System.out.println("Error: " + ex.getMessage());
return 0;
});
// 非阻塞获取结果
combined.thenAccept(sum -> System.out.println("Sum: " + sum));
// 阻塞等待任务完成(仅演示)
combined.get();
}
}