Java CompletableFuture 使用详解
CompletableFuture 是 Java 8 引入的异步编程工具,它实现了 Future 和 CompletionStage 接口,提供了强大的异步编程能力。
1. 基础创建方式
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
public class CompletableFutureBasics {
// 1. 直接创建已完成的 Future
public static void completedFutureExample() {
CompletableFuture<String> future = CompletableFuture.completedFuture("Hello");
try {
System.out.println(future.get()); // 输出: Hello
} catch (Exception e) {
e.printStackTrace();
}
}
// 2. 使用 runAsync 执行无返回值的异步任务
public static void runAsyncExample() {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
System.out.println("异步任务执行中...");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("异步任务完成");
});
future.join(); // 等待任务完成
}
// 3. 使用 supplyAsync 执行有返回值的异步任务
public static void supplyAsyncExample() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "异步任务结果";
});
try {
String result = future.get(); // 阻塞获取结果
System.out.println("结果: " + result);
} catch (Exception e) {
e.printStackTrace();
}
}
}
2. 回调处理(链式操作)
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class CallbackExample {
public static void thenApplyExample() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
// thenApply: 转换结果
CompletableFuture<String> greetingFuture = future.thenApply(s -> s + " World");
// thenAccept: 消费结果,无返回值
greetingFuture.thenAccept(s -> System.out.println("结果: " + s));
// thenRun: 任务完成后执行,不关心结果
greetingFuture.thenRun(() -> System.out.println("任务完成"));
greetingFuture.join();
}
public static void thenComposeExample() {
// thenCompose: 组合两个 Future,第二个依赖于第一个的结果
CompletableFuture<String> future = getUserInfo("123")
.thenCompose(user -> getOrderInfo(user));
future.thenAccept(System.out::println).join();
}
private static CompletableFuture<String> getUserInfo(String userId) {
return CompletableFuture.supplyAsync(() -> "用户" + userId);
}
private static CompletableFuture<String> getOrderInfo(String user) {
return CompletableFuture.supplyAsync(() -> user + "的订单信息");
}
}
3. 组合多个 Future
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class CombineExample {
public static void thenCombineExample() {
// thenCombine: 组合两个独立的 Future
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "World";
});
// 组合两个结果
CompletableFuture<String> combined = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);
System.out.println(combined.join()); // 输出: Hello World
}
public static void allOfExample() {
// allOf: 等待所有 Future 完成
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "结果1");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "结果2");
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "结果3");
CompletableFuture<Void> allFutures = CompletableFuture.allOf(future1, future2, future3);
allFutures.thenRun(() -> {
try {
System.out.println("所有任务完成: " + future1.get() + ", " + future2.get() + ", " + future3.get());
} catch (Exception e) {
e.printStackTrace();
}
}).join();
}
public static void anyOfExample() {
// anyOf: 任意一个 Future 完成即可
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "结果1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "结果2";
});
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
System.out.println("最先完成的结果: " + anyFuture.join()); // 输出: 结果2
}
}
4. 异常处理
java
import java.util.concurrent.CompletableFuture;
public class ExceptionHandlingExample {
public static void exceptionallyExample() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("发生异常");
}
return "正常结果";
});
// exceptionally: 发生异常时提供默认值
CompletableFuture<String> safeFuture = future.exceptionally(ex -> {
System.out.println("捕获异常: " + ex.getMessage());
return "默认值";
});
System.out.println(safeFuture.join()); // 输出: 默认值
}
public static void handleExample() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 这里可能会成功,也可能会失败
return "正常结果";
// throw new RuntimeException("发生异常");
});
// handle: 无论成功还是失败都会执行
CompletableFuture<String> handledFuture = future.handle((result, ex) -> {
if (ex != null) {
return "异常处理结果";
}
return "处理后的: " + result;
});
System.out.println(handledFuture.join());
}
public static void whenCompleteExample() {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// throw new RuntimeException("测试异常");
return "成功结果";
});
// whenComplete: 任务完成后执行,可获取结果和异常
future.whenComplete((result, ex) -> {
if (ex != null) {
System.out.println("任务异常: " + ex.getMessage());
} else {
System.out.println("任务成功: " + result);
}
}).join();
}
}
5. 超时处理(Java 9+)
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
public class TimeoutExample {
public static void orTimeoutExample() {
// orTimeout: Java 9+ 的超时方法
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "慢任务结果";
}).orTimeout(1, TimeUnit.SECONDS) // 设置1秒超时
.exceptionally(ex -> {
if (ex instanceof TimeoutException) {
return "超时,返回默认值";
}
return "其他异常";
});
System.out.println(future.join()); // 输出: 超时,返回默认值
}
public static void completeOnTimeoutExample() {
// completeOnTimeout: 超时时完成并返回默认值
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "慢任务结果";
}).completeOnTimeout("超时默认值", 1, TimeUnit.SECONDS);
System.out.println(future.join()); // 输出: 超时默认值
}
}
6. 实际应用示例
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.ArrayList;
import java.util.stream.Collectors;
public class PracticalExample {
// 自定义线程池
private static final ExecutorService executor = Executors.newFixedThreadPool(10);
public static void parallelTasksExample() {
List<String> ids = List.of("1", "2", "3", "4", "5");
// 并行查询多个ID的信息
List<CompletableFuture<String>> futures = ids.stream()
.map(id -> CompletableFuture.supplyAsync(() -> queryDatabase(id), executor))
.collect(Collectors.toList());
// 等待所有查询完成
List<String> results = futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList());
System.out.println("查询结果: " + results);
}
private static String queryDatabase(String id) {
try {
TimeUnit.MILLISECONDS.sleep(500); // 模拟数据库查询
} catch (InterruptedException e) {
e.printStackTrace();
}
return "数据" + id;
}
public static void pipelineExample() {
// 构建处理流水线
CompletableFuture<String> pipeline = CompletableFuture
.supplyAsync(() -> "原始数据", executor)
.thenApplyAsync(data -> data + " -> 步骤1处理", executor)
.thenApplyAsync(data -> data + " -> 步骤2处理", executor)
.thenApplyAsync(data -> data + " -> 步骤3处理", executor)
.thenApplyAsync(data -> data + " -> 完成", executor);
System.out.println("流水线结果: " + pipeline.join());
}
public static void shutdown() {
executor.shutdown();
}
public static void main(String[] args) {
try {
parallelTasksExample();
pipelineExample();
} finally {
shutdown();
}
}
}
7. 最佳实践
- 使用自定义线程池:避免使用默认的 ForkJoinPool,防止影响其他任务
- 合理处理异常:使用 exceptionally、handle 等方法处理异常
- 避免阻塞:尽量使用 thenApply、thenAccept 等非阻塞方法
- 资源清理:及时关闭自定义的 ExecutorService
- 避免嵌套过深:保持链式调用的可读性
8. 主要方法总结
| 方法 | 描述 |
|---|---|
supplyAsync() |
异步执行有返回值的任务 |
runAsync() |
异步执行无返回值的任务 |
thenApply() |
对结果进行转换 |
thenAccept() |
消费结果,无返回值 |
thenRun() |
任务完成后执行,不关心结果 |
thenCompose() |
组合两个有依赖关系的 Future |
thenCombine() |
组合两个独立的 Future |
allOf() |
等待所有 Future 完成 |
anyOf() |
任意一个 Future 完成即可 |
exceptionally() |
异常处理 |
handle() |
处理结果和异常 |
whenComplete() |
完成后执行回调 |
CompletableFuture 使得异步编程变得更加简洁和强大,是 Java 并发编程中的重要工具。