关于多线程CompletableFuture的使用

本文详细介绍了Java中的CompletableFuture类,包括其基本用法、异常处理、批量任务处理等高级特性。通过多个示例代码展示了如何使用CompletableFuture进行异步编程。
CompletableFuture.runAsync(Runnable runnable);
CompletableFuture.runAsync(Runnable runnable, Executor executor);
 
CompletableFuture.supplyAsync(Supplier<U> supplier);
CompletableFuture.supplyAsync(Supplier<U> supplier, Executor executor)

runAsync 方法接收的是 Runnable 的实例,意味着它没有返回值
supplyAsync 方法对应的是有返回值的情况
这两个方法的带 executor 的变种,表示让任务在指定的线程池中执行,不指定的话,通常任务是在 ForkJoinPool.commonPool() 线程池中执行的。

CompletableFuture.runAsync(() -> {}).thenRun(() -> {}); 
CompletableFuture.runAsync(() -> {}).thenAccept(resultA -> {}); 
CompletableFuture.runAsync(() -> {}).thenApply(resultA -> "resultB");
 
CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB");

前面 3 行代码演示的是,任务 A 无返回值,所以对应的,第 2 行和第 3 行代码中,resultA 其实是 null。

第 4 行用的是 thenRun(Runnable runnable),任务 A 执行完执行 B,并且 B 不需要 A 的结果。

第 5 行用的是 thenAccept(Consumer action),任务 A 执行完执行 B,B 需要 A 的结果,但是任务 B 不返回值。

第 6 行用的是 thenApply(Function fn),任务 A 执行完执行 B,B 需要 A 的结果,同时任务 B 有返回值。

这一小节说完了,如果任务 B 后面还有任务 C,往下继续调用 .thenXxx() 即可。

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);

上面的代码中,任务 A、B、C、D 依次执行,如果任务 A 抛出异常(当然上面的代码不会抛出异常),那么后面的任务都得不到执行。如果任务 C 抛出异常,那么任务 D 得不到执行。

那么我们怎么处理异常呢?看下面的代码,我们在任务 A 中抛出异常,并对其进行处理:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    throw new RuntimeException();
})
        .exceptionally(ex -> "errorResultA")
        .thenApply(resultA -> resultA + " resultB")
        .thenApply(resultB -> resultB + " resultC")
        .thenApply(resultC -> resultC + " resultD");
 
System.out.println(future.join());
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "resultA")
        .thenApply(resultA -> resultA + " resultB")
        // 任务 C 抛出异常
        .thenApply(resultB -> {throw new RuntimeException();})
        // 处理任务 C 的返回值或异常
        .handle(new BiFunction<Object, Throwable, Object>() {
            @Override
            public Object apply(Object re, Throwable throwable) {
                if (throwable != null) {
                    return "errorResultC";
                }
                return re;
            }
        })
        .thenApply(resultC -> resultC + " resultD");
 
System.out.println(future.join());
如果是批量的任务
 无返回值的情况下使用
CompletableFuture.allOf()
有返回值使用,但是只会返回首先执行完的那一个
CompletableFuture.anyOf

上边都是抄袭,以下是我写的demo

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
// 这个是线程池
public class ThreadPoolUtils {

    public static ExecutorService threadPool = new ThreadPoolExecutor(1, 10, 60L, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(1000), Executors.defaultThreadFactory(),
            /
<think>我们参考用户提供的引用内容,特别是引用[1][2][3]中关于CompletableFuture的介绍,来回答如何在Java使用CompletableFuture进行多线程编程。 用户的问题:如何在Java使用CompletableFuture实现多线程编程? 回答结构: 1. 介绍CompletableFuture是什么,以及它的优势。 2. 如何创建CompletableFuture对象。 3. 如何组合多个CompletableFuture(链式调用、组合多个异步任务)。 4. 异常处理。 5. 示例代码。 6. 总结和建议。 注意:使用中文回答,并按照要求添加引用标识。</think>### Java使用CompletableFuture实现多线程编程指南 CompletableFutureJava 8引入的异步编程工具,通过非阻塞式任务处理和链式调用,大幅简化多线程开发。其核心优势包括: 1. **非阻塞调用**:避免线程等待,提高CPU利用率[^3] 2. **链式组合**:支持多个异步任务串联/并联执行[^3] 3. **异常处理**:内置`exceptionally()`方法简化错误恢复[^3] 4. **流式API**:代码更简洁易读(相比传统`Thread`/`Runnable`)[^4] 以下是具体实现步骤: #### 1. **创建CompletableFuture对象** 通过静态工厂方法初始化异步任务: ```java // 无返回值任务 CompletableFuture<Void> future1 = CompletableFuture.runAsync(() -> { System.out.println("异步任务1执行"); }); // 带返回值任务(推荐使用线程池) ExecutorService pool = Executors.newFixedThreadPool(4); CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> { return "异步任务2结果"; }, pool); ``` - `runAsync`:适用于无返回值的Runnable任务 - `supplyAsync`:适用于有返回值的Supplier任务(可指定线程池)[^2] #### 2. **任务结果处理(链式调用)** 通过回调方法处理异步结果: ```java CompletableFuture.supplyAsync(() -> "Hello") .thenApply(s -> s + " World") // 转换结果:输入输出均为值 .thenAccept(System.out::println) // 消费结果:输入值,无输出 .thenRun(() -> System.out.println("处理完成")); // 无输入输出 ``` - `thenApply`:类似`map`操作,转换结果值 - `thenAccept`:类似`forEach`,消费结果 - `thenRun`:任务完成后触发动作[^3] #### 3. **组合多个任务** **并联组合**:等待所有/任意任务完成 ```java // 等待所有任务完成 CompletableFuture<Void> all = CompletableFuture.allOf(future1, future2); all.thenRun(() -> System.out.println("全部任务完成")); // 任意任务完成即触发 CompletableFuture<Object> any = CompletableFuture.anyOf(future1, future2); any.thenAccept(result -> System.out.println("首个完成结果:" + result)); ``` **串联组合**:依赖前序任务结果 ```java future1.thenCompose(v -> CompletableFuture.supplyAsync(() -> "串联任务") ).thenAccept(System.out::println); ``` #### 4. **异常处理** 通过`exceptionally()`或`handle()`捕获异常: ```java CompletableFuture.supplyAsync(() -> { if (Math.random() > 0.5) throw new RuntimeException("模拟异常"); return "成功结果"; }).exceptionally(ex -> { System.err.println("错误: " + ex.getMessage()); return "默认值"; }).thenAccept(System.out::println); ``` - `exceptionally()`:仅处理异常,返回备用值 - `handle()`:同时处理正常结果和异常[^3] #### 5. **完整示例** ```java public class CompletableFutureDemo { public static void main(String[] args) { // 创建线程池 ExecutorService pool = Executors.newFixedThreadPool(2); // 任务1:生成随机数 CompletableFuture<Integer> task1 = CompletableFuture.supplyAsync(() -> { int num = (int)(Math.random() * 100); System.out.println("生成数字: " + num); return num; }, pool); // 任务2:数字加倍(依赖任务1结果) CompletableFuture<Integer> task2 = task1.thenApplyAsync(n -> { System.out.println("加倍计算: " + n * 2); return n * 2; }, pool); // 异常处理 task2.exceptionally(ex -> { System.out.println("计算失败: " + ex.getMessage()); return -1; }); // 关闭线程池(实际项目应复用线程池) pool.shutdown(); } } ``` #### 6. **最佳实践** 1. **线程池管理**: - 始终指定自定义线程池(避免使用默认`ForkJoinPool`) - I/O密集型任务建议使用`newCachedThreadPool` - 计算密集型任务建议使用`newFixedThreadPool`[^3] 2. **资源释放**: ```java try (ExecutorService pool = Executors.newVirtualThreadPerTaskExecutor()) { CompletableFuture.supplyAsync(/*...*/, pool); } // 自动关闭(Java 21+) ``` 3. **性能优化**: - 对耗时操作使用`thenApplyAsync`避免阻塞调用线程 - 合并多个I/O操作用`thenCompose`减少线程切换
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值