摘要:本文主要介绍jdk21
如何优雅的处理异步执行任务;下面给出了几个常见的案例。
CompletableFuture
解决回调地狱写法
顺序执行(前阶段结果传递给后阶段)
适用于需要按顺序执行异步操作的场景(如:先查用户,再查订单)。
方法 | 描述 |
---|---|
thenApply(Function) | 同步处理前阶段结果,返回新结果(有入参、有返回值)。 |
thenAccept(Consumer) | 同步消费前阶段结果,无返回值(有入参、无返回值)。 |
thenRun(Runnable) | 前阶段完成后执行操作,不依赖结果(无入参、无返回值)。 |
thenCompose(Function) | 合并两个阶段为链式调用(前阶段返回CompletableFuture,直接衔接后阶段)。 |
案例
csharp
public void test01(){
CompletableFuture<OrderDto> orderDtoCompletableFuture = CompletableFuture.supplyAsync(() -> {
OrderDto orderDto = new OrderDto();
System.out.println(Thread.currentThread().getName());
orderDto.setId(1L);
return orderDto;
}).thenApplyAsync(orderDto -> {
try{
Thread.sleep(2000L);
}catch (Exception ex){
}
orderDto.setName("测试");
System.out.println("模拟执行耗时,查询商品信息");
return orderDto;
}).thenApplyAsync(orderDto -> {
try{
Thread.sleep(2000L);
}catch (Exception ex){
}
orderDto.setMoney(new BigDecimal("20"));
System.out.println("模拟执行耗时,计算商品总价");
return orderDto;
}).exceptionally(ex -> {
log.error("执行异常", ex);
return null;
});
OrderDto or = orderDtoCompletableFuture.join();
System.out.println(or);
System.out.println("主线程执行完了");
}
并行执行(多阶段独立执行后合并)
适用于并行处理多个任务后合并结果的场景(如:同时计算用户积分和统计订单)。
方法 | 描述 |
---|---|
thenCombine(CompletableFuture, BiFunction) | 等待两个阶段都完成,合并结果(前阶段结果 + 后阶段结果 → 新结果)。 |
allOf(CompletableFuture...) | 等待所有阶段完成(无返回值,需手动收集结果)。 |
anyOf(CompletableFuture...) | 等待任意一个阶段完成(返回第一个完成的结果)。 |
案例
ini
// 阶段 1:计算用户积分(异步)
CompletableFuture<Integer> pointsFuture = CompletableFuture.supplyAsync(() ->
calculatePoints(user)
);
// 阶段 2:统计有效订单数(异步)
CompletableFuture<Integer> validOrdersFuture = CompletableFuture.supplyAsync(() ->
countValidOrders(user)
);
// 合并两个阶段的结果(总积分 = 积分 + 订单数×10)
CompletableFuture<Integer> totalFuture = pointsFuture.thenCombine(
validOrdersFuture,
(points, orders) -> points + orders * 10
);
int total = totalFuture.join(); // 输出总结果
异常处理
链式调用中若某阶段抛出异常,后续阶段会被静默取消,需通过以下方法捕获异常:
方法 | 描述 |
---|---|
exceptionally(Function) | 异常时返回默认值(类似 try-catch 的 catch 块)。 |
handle(BiFunction) | 无论成功或失败都处理(可返回新结果或默认值)。 |
案例
arduino
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (condition) throw new RuntimeException("查询失败");
return "正常数据";
}).exceptionally(ex -> {
System.out.println("异常处理:" + ex.getMessage());
return "默认数据"; // 异常时返回默认值
});
String result = future.join(); // 若异常,返回 "默认数据"
虚线程使用案例
虚线程异步执行并等待结果
ini
public class VirtualThreadCompletableFutureDemo {
public static void main(String[] args) {
ExecutorService virtualExecutor = Executors.newVirtualThreadPerTaskExecutor();
List<CompletableFuture<Void>> futures = new ArrayList<>();
// 提交 3 个虚线程任务
for (int i = 0; i < 3; i++) {
int taskId = i;
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000); // 模拟任务执行
System.out.println("任务 " + taskId + " 完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}, virtualExecutor);
futures.add(future);
}
// 判断所有任务是否完成(阻塞等待)
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
System.out.println("所有任务完成!");
virtualExecutor.shutdown();
}
}
结果
任务 0 完成
任务 1 完成
任务 2 完成
所有任务完成!
扩展:单个任务异常判断
arduino
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("任务失败"); // 模拟异常
}, virtualExecutor);
future.whenComplete((result, ex) -> {
if (ex != null) {
System.out.println("任务异常:" + ex.getMessage()); // 输出:任务异常:任务失败
}
});
// 主动检查是否异常完成
if (future.isCompletedExceptionally()) {
System.out.println("任务因异常终止");
}