CompletableFuture
以下是使用 Java 中 CompletableFuture 实现四个线程顺序执行的代码示例,模拟叫车业务的四个步骤:
java
import java.util.concurrent.CompletableFuture;
public class ThreadOrderExecutionDemo {
// 线程A:检查用户定位是否有效
public static CompletableFuture<Boolean> checkLocationValid() {
return CompletableFuture.supplyAsync(() -> {
System.out.println("线程A:检查用户定位...");
// 模拟业务逻辑,这里假设定位有效
return true;
});
}
// 线程B:匹配附近司机
public static CompletableFuture<String> matchDriver(Boolean isLocationValid) {
return CompletableFuture.supplyAsync(() -> {
if (!isLocationValid) {
throw new RuntimeException("定位无效,无法匹配司机");
}
System.out.println("线程B:匹配附近司机...");
// 模拟匹配到司机,返回司机ID
return "司机ID_123";
});
}
// 线程C:发送订单请求给司机
public static CompletableFuture<Boolean> sendOrderRequest(String driverId) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("线程C:向司机 " + driverId + " 发送订单请求...");
// 模拟发送成功
return true;
});
}
// 线程D:更新客户端已匹配司机状态
public static CompletableFuture<Void> updateClientStatus(Boolean isOrderSent) {
return CompletableFuture.runAsync(() -> {
if (isOrderSent) {
System.out.println("线程D:更新客户端为已匹配司机状态");
} else {
System.out.println("线程D:订单发送失败,客户端状态未更新");
}
});
}
public static void main(String[] args) {
CompletableFuture<Void> result = checkLocationValid()
.thenCompose(ThreadOrderExecutionDemo::matchDriver)
.thenCompose(ThreadOrderExecutionDemo::sendOrderRequest)
.thenCompose(ThreadOrderExecutionDemo::updateClientStatus);
// 等待所有流程执行完成
result.join();
System.out.println("叫车业务流程执行完成");
}
}
代码说明
checkLocationValid方法:模拟检查用户定位的线程A,返回定位是否有效。matchDriver方法:模拟匹配司机的线程B,依赖线程A的定位结果,若定位无效则抛出异常。sendOrderRequest方法:模拟发送订单的线程C,依赖线程B的司机匹配结果。updateClientStatus方法:模拟更新客户端状态的线程D,依赖线程C的订单发送结果。main方法 :通过CompletableFuture的thenCompose方法实现线程的顺序编排,确保一个线程执行完成后再执行下一个线程,同时保持整体的并发能力(其他业务可并行处理)。
从核心定位、常用方法分类、实战示例三个维度梳理。
CompletableFuture是Java 8为解决传统Future只能阻塞获取结果、无法异步回调的痛点设计的异步编程工具,它实现了Future和CompletionStage接口,支持链式调用、异步回调、多任务组合,是处理异步任务的核心类。
一、核心方法分类与用法
我把CompletableFuture的核心方法分为4大类,每类配可直接运行的示例代码,方便你理解。
1. 基础:创建异步任务
用于启动一个异步任务,核心是两个方法(区别:是否有返回值)。
| 方法 | 作用 | 示例 |
|---|---|---|
supplyAsync(Supplier<U>) |
异步执行有返回值的任务 | 获取异步计算结果 |
runAsync(Runnable) |
异步执行无返回值的任务 | 异步执行日志记录、通知等操作 |
示例代码:
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 1. supplyAsync:有返回值的异步任务(比如模拟查询商品价格)
CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作(比如调用远程接口)
try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
return 99; // 商品价格
});
System.out.println("异步获取价格:" + priceFuture.get()); // 阻塞获取结果(仅演示,实际少用)
// 2. runAsync:无返回值的异步任务(比如模拟发送通知)
CompletableFuture<Void> notifyFuture = CompletableFuture.runAsync(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
System.out.println("异步发送订单通知完成");
});
notifyFuture.get(); // 等待任务完成
}
}
2. 核心:结果处理/转换
任务执行完成后,对结果进行转换、消费或异常处理(非阻塞回调)。
| 方法 | 作用 | 特点 |
|---|---|---|
thenApply(Function<T,U>) |
转换结果(输入T,输出U) | 有入参、有返回值 |
thenAccept(Consumer<T>) |
消费结果(输入T) | 有入参、无返回值 |
thenRun(Runnable) |
任务完成后执行(无参数) | 无入参、无返回值 |
whenComplete(BiConsumer<T,Throwable>) |
处理结果+异常(不改变结果) | 可捕获异常,返回原结果 |
exceptionally(Function<Throwable,T>) |
异常兜底(返回默认值) | 异常时触发,返回替代结果 |
示例代码(基于上面的priceFuture扩展):
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> {
// 模拟异常场景:随机抛出异常
if (Math.random() > 0.5) {
throw new RuntimeException("查询价格失败");
}
return 99;
});
// 1. thenApply:转换结果(价格→价格+运费)
CompletableFuture<Integer> totalPriceFuture = priceFuture.thenApply(price -> price + 10);
// 2. whenComplete:处理结果+异常(仅打印,不改变结果)
totalPriceFuture.whenComplete((totalPrice, ex) -> {
if (ex != null) {
System.out.println("处理价格失败:" + ex.getMessage());
} else {
System.out.println("最终总价:" + totalPrice);
}
});
// 3. exceptionally:异常兜底(失败时返回默认价格)
CompletableFuture<Integer> finalFuture = totalPriceFuture.exceptionally(ex -> 0);
System.out.println("兜底后的价格:" + finalFuture.get());
}
3. 进阶:多任务组合
处理多个异步任务的依赖或并行关系,是CompletableFuture最强大的特性。
| 方法 | 作用 | 适用场景 |
|---|---|---|
thenCompose(Function<T,CompletableFuture<U>>) |
串联依赖任务(任务B依赖任务A的结果) | 先查订单→再查订单详情 |
thenCombine(CompletableFuture<U>, BiFunction<T,U,V>) |
合并两个独立任务的结果 | 并行查商品价格和库存,合并结果 |
allOf(CompletableFuture<?>...) |
等待所有任务完成(无返回值) | 并行处理多个无依赖的任务(如批量更新) |
anyOf(CompletableFuture<?>...) |
等待任一任务完成(返回第一个完成的结果) | 多渠道查询数据,取最快的那个 |
示例代码:
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 任务1:查询商品价格
CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> 99);
// 任务2:查询商品库存(独立任务)
CompletableFuture<Integer> stockFuture = CompletableFuture.supplyAsync(() -> 1000);
// 1. thenCombine:合并两个独立任务的结果
CompletableFuture<String> combineFuture = priceFuture.thenCombine(stockFuture, (price, stock) -> {
return "商品价格:" + price + ",库存:" + stock;
});
System.out.println(combineFuture.get()); // 输出:商品价格:99,库存:1000
// 2. thenCompose:串联依赖任务(先查价格→再算折扣价)
CompletableFuture<Integer> discountFuture = priceFuture.thenCompose(price -> {
// 第二个任务依赖第一个任务的结果
return CompletableFuture.supplyAsync(() -> price * 9 / 10);
});
System.out.println("折扣价:" + discountFuture.get()); // 输出:折扣价:89
// 3. allOf:等待所有任务完成(无返回值)
CompletableFuture<Void> allFuture = CompletableFuture.allOf(priceFuture, stockFuture, discountFuture);
allFuture.get(); // 等待所有任务完成
System.out.println("所有任务执行完毕");
// 4. anyOf:取第一个完成的任务结果
CompletableFuture<String> fastFuture1 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) {}
return "渠道1结果";
});
CompletableFuture<String> fastFuture2 = CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {}
return "渠道2结果";
});
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(fastFuture1, fastFuture2);
System.out.println("最快的结果:" + anyFuture.get()); // 输出:渠道2结果
}
4. 结果获取:get() vs join()
这两个方法都用于获取异步任务结果,核心区别是异常处理:
get():抛出InterruptedException和ExecutionException(检查异常),必须捕获或声明抛出;join():抛出非检查异常(CompletionException),无需捕获,更适合流式调用。
示例:
java
// get()需要捕获异常
try {
Integer price = priceFuture.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// join()无需捕获异常(推荐在流式调用中使用)
Integer price = priceFuture.join();
二、关键注意事项
-
线程池 :
supplyAsync/runAsync默认使用ForkJoinPool.commonPool(),如果任务耗时久/数量多,建议自定义线程池(避免占用公共线程池):java// 自定义线程池 ExecutorService executor = Executors.newFixedThreadPool(5); CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 99, executor); -
异常处理 :务必通过
whenComplete/exceptionally处理异常,否则异步任务的异常会被吞掉,难以排查; -
避免阻塞 :尽量使用回调方法(thenApply/thenAccept等)替代
get()/join()阻塞获取结果,发挥异步优势。
总结
- CompletableFuture核心分为4类方法:创建任务(supplyAsync/runAsync)、结果处理(thenApply/exceptionally)、任务组合(thenCompose/allOf)、结果获取(get/join);
thenCompose用于串联依赖任务,thenCombine用于合并独立任务,allOf/anyOf用于多任务批量处理;- 优先使用
join()(非检查异常)和自定义线程池,同时做好异常兜底。