1 CompletableFuture 简介
CompletableFuture
是 Java 8 引入的一个强大的异步编程工具,它实现了 Future
和 CompletionStage
接口。Future
接口用于表示一个异步任务的引用,而 CompletionStage
接口则定义了多种异步方法,使得 CompletableFuture
能够支持复杂的异步任务链和回调机制。
1.1 CompletableFuture 的特点
- 非阻塞:
CompletableFuture
允许任务在主线程之外的线程中运行,并通过回调机制在主线程中获取任务的执行状态、是否完成、是否异常等信息。 - 灵活的回调机制:支持多种回调方法,如
thenApply
、thenAccept
、thenRun
等,可以在任务完成后执行额外的操作。 - 链式调用:支持将多个异步任务串联起来,形成一个链式的 pipeline 调用。
- 合并多个 Future:支持将多个
CompletableFuture
合并,并在所有任务完成后执行某些操作。 - 异常处理:提供了异常处理的 API,可以更好地定位和处理异步任务中的异常。
2 Future 与 CompletableFuture
2.1 Future 的缺点
- 不支持手动完成:无法手动通知正在执行的线程任务结果,必须主动取消或一直等待任务完成。
- 不支持进一步的非阻塞调用:通过
Future.get()
方法会一直阻塞直到任务完成,无法在获取任务结果后执行额外的任务。 - 不支持链式调用:无法将一个
Future
的结果传递给下一个Future
进行处理。 - 不支持多个 Future 合并:无法在多个
Future
并行执行完毕后执行某些操作。 - 不支持异常处理:
Future
的 API 没有任何异常处理的机制,难以定位和处理异步任务中的异常。
2.2 CompletableFuture 的优势
- 手动完成:可以通过
complete
方法手动完成任务,并通知等待的线程。 - 非阻塞调用:支持多种回调方法,如
thenApply
、thenAccept
、thenRun
等,可以在任务完成后执行额外的操作。 - 链式调用:支持将多个异步任务串联起来,形成一个链式的 pipeline 调用。
- 合并多个 Future:支持将多个
CompletableFuture
合并,并在所有任务完成后执行某些操作。 - 异常处理:提供了异常处理的 API,如
exceptionally
、handle
等,可以更好地定位和处理异步任务中的异常。
3 CompletableFuture 的基本用法
3.1 创建 CompletableFuture
CompletableFuture<String> future = new CompletableFuture<>();
3.2 手动完成任务
future.complete("Task completed");
3.3 异步执行任务
- 没有返回值的异步任务:使用
CompletableFuture.runAsync()
- 有返回值的异步任务:使用
CompletableFuture.supplyAsync()
// 没有返回值的异步任务
CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
System.out.println("Running async task");
});
// 有返回值的异步任务
CompletableFuture<String> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
return "Task result";
});
3.4 回调方法
- 线程依赖:当一个线程依赖另一个线程时,可以使用
thenApply
方法来把这两个线程串行化。 - 消费处理结果:
thenAccept
消费处理结果,接收任务的处理结果,并消费处理,无返回结果。
// 线程依赖
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "Task result");
future.thenApply(result -> {
return result.toUpperCase();
}).thenAccept(result -> {
System.out.println("Processed result: " + result);
});
3.5 异常处理
exceptionally
:异常处理,出现异常时触发。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
if (true) {
throw new RuntimeException("Exception occurred");
}
return "Task result";
});
future.exceptionally(ex -> {
System.out.println("Exception occurred: " + ex.getMessage());
return "Default value";
}).thenAccept(result -> {
System.out.println("Final result: " + result);
});
3.6 合并多个 Future
thenCompose
:合并两个有依赖关系的CompletableFuture
的执行结果。allOf
:一系列独立的CompletableFuture
任务,等其所有的任务执行完后做一些事情。anyOf
:只要在多个CompletableFuture
里面有一个返回,整个任务就可以结束,而不需要等到每一个CompletableFuture
结束。
// thenCompose
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Result 1");
CompletableFuture<String> future2 = future1.thenCompose(result ->
CompletableFuture.supplyAsync(() -> result + " Result 2")
);
// allOf
CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> "Result A");
CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> "Result B");
CompletableFuture<Void> allOfFuture = CompletableFuture.allOf(futureA, futureB);
allOfFuture.thenRun(() -> {
System.out.println("All tasks completed");
});
// anyOf
CompletableFuture<String> futureX = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Result X";
});
CompletableFuture<String> futureY = CompletableFuture.supplyAsync(() -> "Result Y");
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(futureX, futureY);
anyOfFuture.thenAccept(result -> {
System.out.println("First completed task result: " + result);
});
4 案例
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 异步调用 没有返回值
CompletableFuture<Void> completableFuture1 = CompletableFuture.runAsync(()->{
System.out.println(Thread.currentThread().getName()+" completableFuture1");
});
completableFuture1.get();
// 异步调用 有返回值
CompletableFuture<Integer> completableFuture2 = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+" completableFuture2");
// 模拟异常
int i = 1/0;
return 1024;
});
completableFuture2.whenComplete((t,u)->{
System.out.println("----t=" + t);
System.out.println("----u=" + u);
}).get();
}
}