CompletableFuture 用法详解
CompletableFuture 是 Java 8 引入的异步编程工具,实现了 Future 和 CompletionStage 接口,解决了传统 Future 只能阻塞获取结果、无法链式调用的问题,支持异步执行、链式处理、多任务组合等能力,是 Java 异步编程的核心工具之一。
一、核心优势
- 非阻塞获取结果:支持回调函数,无需阻塞等待任务完成。
- 链式调用:多个异步任务可以按顺序链式执行,代码更简洁。
- 多任务组合:支持多个异步任务的并行执行、依赖执行、任意一个完成/全部完成等组合场景。
- 异常处理:提供专门的异常处理方法,避免异常丢失。
二、基本使用:创建异步任务
CompletableFuture 提供了多种静态方法来创建异步任务,主要分为无返回值 和有返回值 两类,底层可指定线程池(默认使用 ForkJoinPool.commonPool())。
1. 无返回值的异步任务
runAsync(Runnable runnable):使用默认线程池执行 Runnable 任务。runAsync(Runnable runnable, Executor executor):使用指定线程池执行 Runnable 任务。
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
public class CompletableFutureDemo {
public static void main(String[] args) throws InterruptedException {
// 使用默认线程池执行无返回值任务
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("任务1执行完成(无返回值)");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 使用自定义线程池执行无返回值任务
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("任务2执行完成(无返回值)");
} catch (InterruptedException e) {
e.printStackTrace();
}
}, Executors.newFixedThreadPool(2));
// 阻塞等待所有任务完成(仅演示,实际不推荐阻塞)
Thread.sleep(2000);
}
}
2. 有返回值的异步任务
supplyAsync(Supplier<U> supplier):使用默认线程池执行 Supplier 任务,返回结果。supplyAsync(Supplier<U> supplier, Executor executor):使用指定线程池执行 Supplier 任务,返回结果。
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
// 使用默认线程池执行有返回值任务
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "任务1返回结果";
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
});
// 使用自定义线程池执行有返回值任务
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return 100;
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}, Executors.newFixedThreadPool(2));
// 获取结果(阻塞式,仅演示,推荐使用回调函数)
System.out.println(future1.get()); // 输出:任务1返回结果
System.out.println(future2.get()); // 输出:100
}
}
三、链式调用:处理任务结果
CompletableFuture 提供了一系列方法来处理异步任务的结果,实现链式调用,核心方法分为同步处理 和异步处理 (方法名带 Async)。
1. thenApply / thenApplyAsync
接收上一个任务的结果,处理后返回新的结果(映射)。
thenApply:在当前线程(或上一个任务的线程)执行。thenApplyAsync:使用默认/指定线程池执行。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
return 10; // 第一步:返回10
}).thenApply(num -> {
return num * 2; // 第二步:乘以2,返回20
}).thenApply(num -> {
return num + 5; // 第三步:加5,返回25
});
System.out.println(future.get()); // 输出:25
}
}
2. thenAccept / thenAcceptAsync
接收上一个任务的结果,消费结果(无返回值,消费)。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return "Hello";
}).thenAccept(str -> {
System.out.println(str + " World"); // 输出:Hello World
});
future.get();
}
}
3. thenRun / thenRunAsync
不接收上一个任务的结果,仅执行后续操作(无参数、无返回值)。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
return 100;
}).thenRun(() -> {
System.out.println("任务执行完成,执行后续操作"); // 输出:任务执行完成,执行后续操作
});
future.get();
}
}
4. thenCompose / thenComposeAsync
处理嵌套的 CompletableFuture (扁平化),与 thenApply 的区别:thenApply 返回普通值,thenCompose 返回 CompletableFuture。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
// 模拟根据数字获取字符串的异步方法
private static CompletableFuture<String> getStringAsync(int num) {
return CompletableFuture.supplyAsync(() -> "数字:" + num);
}
public static void main(String[] args) throws Exception {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> 10)
.thenCompose(num -> getStringAsync(num)); // 扁平化嵌套的CompletableFuture
System.out.println(future.get()); // 输出:数字:10
}
}
5. thenCombine / thenCombineAsync
组合两个独立的 CompletableFuture 结果,处理后返回新结果。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 10);
CompletableFuture<Integer> future2 = CompletableFuture.supplyAsync(() -> 20);
// 组合两个结果,求和
CompletableFuture<Integer> resultFuture = future1.thenCombine(future2, (num1, num2) -> num1 + num2);
System.out.println(resultFuture.get()); // 输出:30
}
}
四、多任务组合
CompletableFuture 支持多个异步任务的组合执行,满足并行处理场景。
1. allOf:等待所有任务完成
无返回值,仅等待所有传入的 CompletableFuture 完成(无论成功/失败)。
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
System.out.println("任务1完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
CompletableFuture<Void> future2 = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(2000);
System.out.println("任务2完成");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
// 等待所有任务完成
CompletableFuture<Void> allFuture = CompletableFuture.allOf(future1, future2);
allFuture.get(); // 阻塞直到所有任务完成
System.out.println("所有任务都完成了");
}
}
2. anyOf:等待任意一个任务完成
返回第一个完成的任务的结果(无论成功/失败)。
java
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
public class CompletableFutureDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
return "任务1结果";
} catch (InterruptedException e) {
return "任务1异常";
}
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
return "任务2结果";
} catch (InterruptedException e) {
return "任务2异常";
}
});
// 等待任意一个任务完成
CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(future1, future2);
System.out.println(anyFuture.get()); // 输出:任务2结果(因为任务2先完成)
}
}
五、异常处理
CompletableFuture 提供了专门的异常处理方法,避免异常丢失。
1. exceptionally
捕获上一个任务的异常,返回默认值(类似 try-catch 的 catch 块)。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模拟异常
int num = 1 / 0;
return num;
}).exceptionally(e -> {
// 捕获异常,返回默认值0
System.out.println("异常信息:" + e.getMessage());
return 0;
});
System.out.println(future.get()); // 输出:0
}
}
2. handle / handleAsync
无论上一个任务成功还是失败,都执行处理逻辑(类似 try-catch-finally 的 finally 块,支持处理结果和异常)。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模拟异常(注释掉则返回10)
// int num = 1 / 0;
return 10;
}).handle((result, e) -> {
if (e != null) {
System.out.println("异常信息:" + e.getMessage());
return -1;
} else {
return result * 2;
}
});
System.out.println(future.get()); // 无异常输出20,有异常输出-1
}
}
3. whenComplete / whenCompleteAsync
无论成功还是失败,都执行回调(不改变结果,仅做通知/日志)。
java
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) throws Exception {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
// 模拟异常
// int num = 1 / 0;
return 10;
}).whenComplete((result, e) -> {
if (e != null) {
System.out.println("任务失败:" + e.getMessage());
} else {
System.out.println("任务成功:" + result);
}
});
System.out.println(future.get()); // 无异常输出10,有异常抛出异常
}
}
六、注意事项
- 线程池选择 :默认使用
ForkJoinPool.commonPool(),核心线程数为 CPU 核心数 - 1,若任务是 IO 密集型,建议使用自定义线程池(如ThreadPoolExecutor),避免线程池耗尽。 - 异常处理 :异步任务的异常不会主动抛出,必须通过
exceptionally、handle等方法处理,否则会导致异常丢失。 - 避免阻塞 :
get()、join()是阻塞方法,尽量使用回调函数(如thenAccept)替代,否则失去异步优势。 - 内存泄漏:若 CompletableFuture 未完成且被长期持有,可能导致线程和资源泄漏,需确保任务能正常完成或超时。
总结
CompletableFuture 是 Java 异步编程的核心工具,通过创建异步任务、链式处理结果、多任务组合、异常处理 等能力,解决了传统 Future 的局限性。在实际开发中,常用于处理 IO 密集型任务(如网络请求、数据库操作)、并行计算等场景,能有效提升程序的并发性能和响应速度。