Future 的局限性
Future 是 Java 5 引入的异步编程接口,虽然它解决了部分异步编程问题,但在实际使用中存在多个明显的局限性:
1. 阻塞获取结果
- Future 只能通过
get()方法阻塞获取结果,这会阻塞调用线程 - 缺乏非阻塞回调机制,无法在任务完成后自动通知
Future<String> future = executor.submit(task);
String result = future.get(); // 阻塞直到结果可用
2. 无法组合多个 Future
- 难以将多个 Future 的结果组合起来
- 实现多个异步任务的依赖关系需要手动编码,代码复杂
Future<String> future1 = service.submit(task1);
Future<String> future2 = service.submit(task2);
String result1 = future1.get(); // 阻塞
String result2 = future2.get(); // 阻塞
String combined = result1 + result2;
3. 缺乏异常处理机制
- 异常只能在调用
get()时捕获,无法提前处理 - 没有提供链式异常处理的方法
4. 无法手动完成
- 不能手动设置 Future 的结果或异常
- 无法实现超时自动完成等场景
5. 没有任务链式调用
- 无法实现"任务A完成后自动触发任务B"的模式
- 每个阶段都需要手动处理,代码冗长
6. 缺乏时间控制
- 没有内置的超时控制(虽然
get()可以带超时参数) - 无法实现"哪个任务先完成就先用哪个"的逻辑
7. 无法取消回调
- 一旦提交任务,难以优雅地取消整个处理链
CompleteFuture
CompletableFuture 是 Java 8 引入的一个异步编程工具类,属于 java.util.concurrent 包,实现了 Future 和 CompletionStage 接口。它代表一个异步计算的结果,并提供了丰富的 API 来组合、转换和处理异步任务
核心特点:
- 非阻塞:支持回调机制,避免
Future.get()的阻塞问题 - 链式调用:可以串联多个异步任务(类似
Stream的流式操作) - 组合操作:支持多个
CompletableFuture的组合(并行、串行、竞速等) - 异常处理:内置
exceptionally()、handle()等方法处理异常 - 手动完成:可以手动设置任务结果(
complete()、completeExceptionally())
创建 CompleteFuture
supplyAsync()- 有返回值的异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
});
// 获取结果(会阻塞)
String result = future.get();
System.out.println(result);
runAsync()- 无返回值的异步任务
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
// 模拟耗时操作
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
System.out.println("异步任务执行完成");
});
// 等待任务完成
future.get();
使用自定义线程池
ExecutorService customExecutor = Executors.newFixedThreadPool(5);
// 使用自定义线程池执行异步任务
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 任务逻辑
return "使用自定义线程池执行的结果";
}, customExecutor); // 默认使用ForkJoinPool.commonPool()
异步任务结果处理
thenApply(Function<T, R>) — 同步转换结果
- 作用:对上一个阶段的结果进行转换,返回一个新的值
- 输入:上一个任务的返回值(
T类型) - 输出:返回转换后的结果(
R类型),可以继续传递给下一个CompletableFuture - 适用场景:需要对结果进行映射或计算,例如字符串转大写、数字运算
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<Integer> result = future.thenApply(s -> s.length()); // 计算字符串长度
System.out.println(result.get()); // 输出 5
thenAccept(Consumer<T>) — 消费结果
- 作用:消费上一个阶段的结果,但不返回新值(返回
void) - 输入:上一个任务的返回值(
T类型) - 输出:无返回值(
CompletableFuture<Void>) - 适用场景:仅需处理结果而不需要返回值的操作,如打印、存储
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<Void> result = future.thenAccept(s -> System.out.println(s)); // 直接消费
result.join(); // 输出 "hello"
thenRun(Runnable) — 无结果执行
- 作用:在上一个阶段完成后执行某个操作,不接收上一个任务的结果,也不返回新值
- 输入:无(不关心前一个任务的结果)
- 输出:无返回值(
CompletableFuture<Void>) - 适用场景:仅需在任务完成后执行某个操作,如日志记录、清理资源
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<Void> result = future.thenRun(() -> System.out.println("Task finished"));
result.join(); // 输出 "Task finished"
以上方法均有对应的异步版本(带
Async后缀,如thenApplyAsync),表示回调会在新的线程中执行,默认使用ForkJoinPool.commonPool()
组合多个 CompleteFuture
thenCompose() — 扁平化处理(链式异步调用)
- 用于链式调用多个
CompletableFuture,避免嵌套(如CompletableFuture<CompletableFuture<T>>)
// 模拟查询订单(返回订单信息,包含 userId)
CompletableFuture<Order> getOrder(String orderId) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询订单: " + orderId);
return new Order(orderId, "user123"); // 假设订单包含 userId
});
}
// 模拟查询用户(返回用户信息)
CompletableFuture<User> getUser(String userId) {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询用户: " + userId);
return new User(userId, "张三", "zhangsan@example.com");
});
}
// 使用 thenCompose 链式调用
CompletableFuture<User> userFuture = getOrder("order-123")
.thenCompose(order -> getUser(order.getUserId())); // 避免嵌套 Future
User user = userFuture.join();
System.out.println("用户信息: " + user);
// 输出:
// 查询订单: order-123
// 查询用户: user123
// 用户信息: User{userId='user123', name='张三', email='zhangsan@example.com'}
thenCombine() — 合并两个独立任务的结果
- 合并 **两个独立的 `CompletableFuture`**,等它们都完成后,再对它们的结果进行组合计算
// 模拟查询推荐商品
CompletableFuture<List<String>> getRecommendations() {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询推荐商品...");
return List.of("iPhone", "MacBook", "AirPods");
});
}
// 模拟查询购物车商品
CompletableFuture<List<String>> getCartItems() {
return CompletableFuture.supplyAsync(() -> {
System.out.println("查询购物车商品...");
return List.of("T-shirt", "Jeans");
});
}
// 使用 thenCombine 合并两个 Future 的结果
CompletableFuture<List<String>> combinedFuture = getRecommendations()
.thenCombine(
getCartItems(),
(recommendations, cartItems) -> {
// 合并推荐商品和购物车商品
List<String> allItems = new ArrayList<>(recommendations);
allItems.addAll(cartItems);
return allItems;
}
);
List<String> allItems = combinedFuture.join();
System.out.println("所有商品: " + allItems);
// 输出:
// 查询推荐商品...
// 查询购物车商品...
// 所有商品: [iPhone, MacBook, AirPods, T-shirt, Jeans]
allOf() — 等待所有 CompletableFuture 完成
- 等待 所有给定的
CompletableFuture完成(不关心它们的返回值) - 返回
CompletableFuture<Void>,仅表示所有任务已完成
public class OrderService {
// 模拟发送短信(异步)
CompletableFuture<Void> sendSMS(String orderId) {
return CompletableFuture.runAsync(() -> {
System.out.println("发送短信通知用户,订单号: " + orderId);
});
}
// 模拟记录日志(异步)
CompletableFuture<Void> logOrder(String orderId) {
return CompletableFuture.runAsync(() -> {
System.out.println("记录订单日志,订单号: " + orderId);
});
}
// 模拟更新库存(异步)
CompletableFuture<Void> updateStock(String orderId) {
return CompletableFuture.runAsync(() -> {
System.out.println("更新库存,订单号: " + orderId);
});
}
// 使用 allOf 等待所有任务完成
public CompletableFuture<Void> processOrder(String orderId) {
CompletableFuture<Void> smsFuture = sendSMS(orderId);
CompletableFuture<Void> logFuture = logOrder(orderId);
CompletableFuture<Void> stockFuture = updateStock(orderId);
return CompletableFuture.allOf(smsFuture, logFuture, stockFuture)
.thenRun(() -> System.out.println("订单处理完成!"));
}
public static void main(String[] args) {
OrderService service = new OrderService();
service.processOrder("order-123").join();
}
}
anyOf() — 等待任意一个 CompletableFuture 完成
- 等待 任意一个给定的
CompletableFuture完成(不管其他任务是否完成) - 返回
CompletableFuture<Object>(因为任务返回类型可能不同) - 多个任务并行执行,只要有一个完成就可以继续(如超时处理、竞速查询)
public class PriceService {
// 模拟从缓存查询(快速,但可能数据过期)
CompletableFuture<Double> getPriceFromCache(String productId) {
return CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(100); // 模拟网络延迟
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("从缓存查询价格");
return 99.9; // 假设缓存中的价格
});
}
// 模拟从数据库查询(较慢,但数据准确)
CompletableFuture<Double> getPriceFromDB(String productId) {
return CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500); // 模拟数据库查询延迟
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("从数据库查询价格");
return 109.9; // 数据库中的价格
});
}
// 模拟从第三方API查询(最慢,但可能更权威)
CompletableFuture<Double> getPriceFromAPI(String productId) {
return CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.MILLISECONDS.sleep(800); // 模拟API延迟
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("从第三方API查询价格");
return 119.9; // 第三方API的价格
});
}
// 使用 anyOf 获取最快返回的价格
public CompletableFuture<Double> getFastestPrice(String productId) {
CompletableFuture<Double> cacheFuture = getPriceFromCache(productId);
CompletableFuture<Double> dbFuture = getPriceFromDB(productId);
CompletableFuture<Double> apiFuture = getPriceFromAPI(productId);
return CompletableFuture.anyOf(cacheFuture, dbFuture, apiFuture)
.thenApply(result -> (Double) result); // 类型转换
}
public static void main(String[] args) {
PriceService service = new PriceService();
Double price = service.getFastestPrice("product-123").join();
System.out.println("最快返回的价格: " + price);
}
}
CompleteFuture 高级特性
异常处理
exceptionally() 方法
exceptionally() 方法允许你提供一个回调函数,当 CompletableFuture 完成时出现异常时调用:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 可能抛出异常的操作
if (Math.random() > 0.5) {
throw new RuntimeException("Oops!");
}
return "Success";
}).exceptionally(ex -> {
System.out.println("Exception occurred: " + ex.getMessage());
return "Recovered Value";
});
System.out.println(safeFuture.join()); // 输出 "Success" 或 "Recovered Value"
handle() 方法
handle() 方法无论 CompletableFuture 是否正常完成都会被调用,可以同时处理正常结果和异常
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 可能抛出异常的操作
if (Math.random() > 0.5) {
throw new RuntimeException("Error!");
}
return "Success";
}).handle((result, ex) -> {
if (ex != null) {
return "Handled: " + ex.getMessage();
}
return "Result: " + result;
});
System.out.println(handledFuture.join());
whenComplete() 方法
whenComplete() 允许你在 CompletableFuture 完成时(无论是正常完成还是异常完成)执行指定的操作
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (Math.random() > 0.5) {
throw new RuntimeException("模拟异常");
}
return "成功结果";
}).whenComplete((result, ex) -> {
if (ex != null) {
System.out.println("任务失败,异常: " + ex.getMessage());
} else {
System.out.println("任务成功,结果: " + result);
}
});