引言:什么是异步编程?
异步编程是一种编程范式,允许程序在等待某些耗时操作(如网络请求、文件读取、数据库查询)完成时,继续执行其他任务,从而提高程序的效率和响应性。
同步 vs 异步类比
同步模式:像点餐后一直在餐厅等菜
- 你点了宫保鸡丁
- 服务员说需要20分钟
- 你就一直坐在那里等
- 等了20分钟后,终于吃到
异步模式:像点外卖
- 你点了宫保鸡丁
- 外卖小哥说需要20分钟
- 你可以做其他事情(工作、看电视)
- 20分钟后外卖到了,你去取
Future/CompletableFuture就是你的"外卖订单":可以用来检查状态和获取结果
Future接口
Future是Java 5引入的接口,表示一个异步计算的结果。你可以提交一个任务给线程池,然后通过Future来检查任务是否完成、获取结果等。
Future接口核心方法
| 方法 | 说明 |
|---|---|
| get() | 阻塞等待并获取结果 |
| get(timeout) | 阻塞等待,带超时 |
| isDone() | 判断是否完成 |
| isCancelled() | 判断是否被取消 |
| cancel(boolean) | 尝试取消任务 |
Future基本用法
import java.util.concurrent.*;
ExecutorService executor = Executors.newFixedThreadPool(2);
// 提交异步任务,返回Future
Future future = executor.submit(() -> {
Thread.sleep(1000); // 模拟耗时操作
return 42 * 2;
});
// 执行其他任务
System.out.println("做其他事情...");
// 通过Future获取结果(会阻塞直到结果可用)
Integer result = future.get();
System.out.println("计算结果: " + result);
executor.shutdown();
Future的局限性
Future的不足:
- 不能手动完成:无法手动设置Future的结果
- 不能链式调用:无法方便地组合多个Future
- 没有异常处理:无法直接处理异步任务的异常
- 轮询判断完成:需要不断调用isDone()来检查状态
CompletableFuture详解
CompletableFuture是Java 8引入的增强版Future,完美解决了Future的局限性,支持函数式编程、链式调用、组合操作和强大的异常处理。
创建CompletableFuture
import java.util.concurrent.CompletableFuture;
// 方式1:使用supplyAsync(有返回值)
CompletableFuture cf1 = CompletableFuture.supplyAsync(() -> {
return "Hello";
});
// 方式2:使用runAsync(无返回值)
CompletableFuture cf2 = CompletableFuture.runAsync(() -> {
System.out.println("执行异步任务");
});
// 方式3:手动完成
CompletableFuture cf3 = new CompletableFuture<>();
cf3.complete("手动设置结果");
CompletableFuture常用方法分类
| 类别 | 方法 | 说明 |
|---|---|---|
| 创建 | supplyAsync(Runnable) | 异步执行,有返回值 |
| runAsync(Runnable) | 异步执行,无返回值 | |
| 转换 | thenApply(Function) | 转换结果 |
| thenApplyAsync() | 异步转换 | |
| 消费 | thenAccept(Consumer) | 消费结果 |
| thenRun(Runnable) | 不关心结果,只执行操作 | |
| 组合 | thenCompose(Function) | 扁平化Future |
| thenCombine(Completion) | 组合两个Future | |
| 异常 | exceptionally(Function) | 处理异常 |
| handle(BiFunction) | 无论成功失败都处理 |
链式调用详解
thenApply - 转换结果
// thenApply:接收上一个结果,进行转换
CompletableFuture cf = CompletableFuture
.supplyAsync(() -> "Hello")
.thenApply(s -> s.length()); // "Hello" -> 5
System.out.println(cf.join()); // 输出 5
// 连续转换
CompletableFuture cf2 = CompletableFuture
.supplyAsync(() -> "Hello World")
.thenApply(s -> s.toUpperCase()) // "HELLO WORLD"
.thenApply(s -> s.length()); // 11
System.out.println(cf2.join()); // 11
thenAccept - 消费结果
// thenAccept:只消费结果,不返回新值
CompletableFuture
.supplyAsync(() -> "Hello")
.thenAccept(s -> System.out.println("收到: " + s));
// thenRun:不关心上一步结果,只执行操作
CompletableFuture
.supplyAsync(() -> 100)
.thenRun(() -> System.out.println("任务完成")); // 只打印,不使用结果
thenCompose - 扁平化Future(链式异步)
// thenCompose:用于返回CompletableFuture的方法,避免嵌套
// 场景:根据用户ID获取用户,再获取用户的订单
// 错误写法(使用thenApply会导致嵌套)
CompletableFuture userFuture = getUserById(1);
CompletableFuture> orderNested = userFuture
.thenApply(user -> getOrderByUserId(user.getId()));
// 正确写法(使用thenCompose扁平化)
CompletableFuture orderFuture = userFuture
.thenCompose(user -> getOrderByUserId(user.getId()));
// 实际示例
CompletableFuture cf = CompletableFuture
.supplyAsync(() -> "Hello")
.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
System.out.println(cf.join()); // "Hello World"
thenCombine - 组合两个Future
// thenCombine:组合两个独立的CompletableFuture
CompletableFuture cf1 = CompletableFuture
.supplyAsync(() -> "Hello");
CompletableFuture cf2 = CompletableFuture
.supplyAsync(() -> "World");
// 等待两个都完成后,合并结果
CompletableFuture combined = cf1
.thenCombine(cf2, (s1, s2) -> s1 + " " + s2);
System.out.println(combined.join()); // "Hello World"
// 更多示例:计算价格
CompletableFuture basePrice = CompletableFuture
.supplyAsync(() -> 100.0);
CompletableFuture tax = CompletableFuture
.supplyAsync(() -> 10.0);
CompletableFuture total = basePrice
.thenCombine(tax, (price, t) -> price + t);
System.out.println("总价: " + total.join()); // 110.0
异常处理
exceptionally - 捕获异常
// exceptionally:处理异常,返回默认值
CompletableFuture cf = CompletableFuture
.supplyAsync(() -> {
if (true) throw new RuntimeException("出错了!");
return 100;
})
.exceptionally(ex -> {
System.out.println("捕获异常: " + ex.getMessage());
return -1; // 返回默认值
});
System.out.println("结果: " + cf.join()); // -1
handle - 无论成功失败都处理
// handle:无论成功还是失败都会执行
CompletableFuture cf = CompletableFuture
.supplyAsync(() -> {
if (true) throw new RuntimeException("失败");
return 100;
})
.handle((result, ex) -> {
if (ex != null) {
System.out.println("发生异常: " + ex.getMessage());
return 0; // 异常时返回0
}
return result; // 成功时返回原结果
});
System.out.println("最终结果: " + cf.join()); // 0
whenComplete - 完成时回调
// whenComplete:完成时的回调(不修改结果)
CompletableFuture cf = CompletableFuture
.supplyAsync(() -> "Hello")
.thenApply(s -> s.toUpperCase())
.whenComplete((result, ex) -> {
if (ex != null) {
System.out.println("异常: " + ex);
} else {
System.out.println("完成,结果: " + result);
}
});
cf.join(); // 输出:完成,结果:HELLO
实战应用场景
场景1:异步获取用户信息
// 模拟异步服务
CompletableFuture getUserById(Long id) {
return CompletableFuture.supplyAsync(() -> {
// 模拟数据库查询
return new User(id, "User" + id);
});
}
CompletableFuture getOrderByUserId(Long userId) {
return CompletableFuture.supplyAsync(() -> {
// 模拟查询订单
return new Order(userId, "Order-001");
});
}
// 链式调用获取用户和订单
getUserById(1L)
.thenCompose(user -> getOrderByUserId(user.getId()))
.thenAccept(order -> System.out.println("订单: " + order))
.exceptionally(ex -> {
System.out.println("错误: " + ex.getMessage());
return null;
})
.join();
场景2:并行获取多个数据源
// 并行获取用户信息、订单、推荐商品
CompletableFuture userFuture = getUserById(1L);
CompletableFuture> ordersFuture = getOrders(1L);
CompletableFuture> recommendFuture = getRecommendations(1L);
// 等待所有完成
CompletableFuture.allOf(userFuture, ordersFuture, recommendFuture)
.thenRun(() -> {
User user = userFuture.join();
List orders = ordersFuture.join();
List products = recommendFuture.join();
System.out.println("用户: " + user);
System.out.println("订单数: " + orders.size());
System.out.println("推荐商品数: " + products.size());
})
.join();
场景3:异步HTTP请求
// 模拟异步HTTP调用
CompletableFuture fetchUserData() {
return CompletableFuture.supplyAsync(() -> {
// 模拟HTTP请求
return "UserData";
});
}
CompletableFuture fetchProductData() {
return CompletableFuture.supplyAsync(() -> {
return "ProductData";
});
}
// 并行获取后合并
CompletableFuture combinedData = fetchUserData()
.thenCombine(fetchProductData(), (user, product) -> {
return user + " + " + product;
});
System.out.println(combinedData.join());
使用线程池
// 默认使用ForkJoinPool.commonPool()(公共线程池)
CompletableFuture cf1 = CompletableFuture
.supplyAsync(() -> "Hello");
// 也可以指定线程池
ExecutorService executor = Executors.newFixedThreadPool(4);
CompletableFuture cf2 = CompletableFuture
.supplyAsync(() -> "World", executor);
// 记得关闭线程池
executor.shutdown();
常用场景总结
thenApply:同步转换结果
thenApplyAsync:异步转换结果
thenAccept:消费结果
thenCompose:链式Future(返回CompletableFuture)
thenCombine:并行Future合并
exceptionally:异常处理
小结
- Future表示异步计算结果,但功能有限
- CompletableFuture是增强版Future,支持函数式编程
- supplyAsync:创建有返回值的异步任务
- runAsync:创建无返回值的异步任务
- thenApply:转换结果
- thenCompose:扁平化Future,链接多个异步操作
- thenCombine:并行执行多个异步操作并合并结果
- exceptionally/handle:异常处理