【多线程编程】

CompletableFuture

以下是使用 Java 中 CompletableFuture 实现四个线程顺序执行的代码示例,模拟叫车业务的四个步骤:

java 复制代码
import java.util.concurrent.CompletableFuture;

public class ThreadOrderExecutionDemo {
    // 线程A:检查用户定位是否有效
    public static CompletableFuture<Boolean> checkLocationValid() {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println("线程A:检查用户定位...");
            // 模拟业务逻辑,这里假设定位有效
            return true;
        });
    }

    // 线程B:匹配附近司机
    public static CompletableFuture<String> matchDriver(Boolean isLocationValid) {
        return CompletableFuture.supplyAsync(() -> {
            if (!isLocationValid) {
                throw new RuntimeException("定位无效,无法匹配司机");
            }
            System.out.println("线程B:匹配附近司机...");
            // 模拟匹配到司机,返回司机ID
            return "司机ID_123";
        });
    }

    // 线程C:发送订单请求给司机
    public static CompletableFuture<Boolean> sendOrderRequest(String driverId) {
        return CompletableFuture.supplyAsync(() -> {
            System.out.println("线程C:向司机 " + driverId + " 发送订单请求...");
            // 模拟发送成功
            return true;
        });
    }

    // 线程D:更新客户端已匹配司机状态
    public static CompletableFuture<Void> updateClientStatus(Boolean isOrderSent) {
        return CompletableFuture.runAsync(() -> {
            if (isOrderSent) {
                System.out.println("线程D:更新客户端为已匹配司机状态");
            } else {
                System.out.println("线程D:订单发送失败,客户端状态未更新");
            }
        });
    }

    public static void main(String[] args) {
        CompletableFuture<Void> result = checkLocationValid()
                .thenCompose(ThreadOrderExecutionDemo::matchDriver)
                .thenCompose(ThreadOrderExecutionDemo::sendOrderRequest)
                .thenCompose(ThreadOrderExecutionDemo::updateClientStatus);

        // 等待所有流程执行完成
        result.join();
        System.out.println("叫车业务流程执行完成");
    }
}

代码说明

  • checkLocationValid 方法:模拟检查用户定位的线程A,返回定位是否有效。
  • matchDriver 方法:模拟匹配司机的线程B,依赖线程A的定位结果,若定位无效则抛出异常。
  • sendOrderRequest 方法:模拟发送订单的线程C,依赖线程B的司机匹配结果。
  • updateClientStatus 方法:模拟更新客户端状态的线程D,依赖线程C的订单发送结果。
  • main 方法 :通过 CompletableFuturethenCompose 方法实现线程的顺序编排,确保一个线程执行完成后再执行下一个线程,同时保持整体的并发能力(其他业务可并行处理)。

核心定位、常用方法分类、实战示例三个维度梳理。

CompletableFuture是Java 8为解决传统Future只能阻塞获取结果、无法异步回调的痛点设计的异步编程工具,它实现了FutureCompletionStage接口,支持链式调用、异步回调、多任务组合,是处理异步任务的核心类。

一、核心方法分类与用法

我把CompletableFuture的核心方法分为4大类,每类配可直接运行的示例代码,方便你理解。

1. 基础:创建异步任务

用于启动一个异步任务,核心是两个方法(区别:是否有返回值)。

方法 作用 示例
supplyAsync(Supplier<U>) 异步执行有返回值的任务 获取异步计算结果
runAsync(Runnable) 异步执行无返回值的任务 异步执行日志记录、通知等操作

示例代码

java 复制代码
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

public class CompletableFutureDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        // 1. supplyAsync:有返回值的异步任务(比如模拟查询商品价格)
        CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> {
            // 模拟耗时操作(比如调用远程接口)
            try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }
            return 99; // 商品价格
        });
        System.out.println("异步获取价格:" + priceFuture.get()); // 阻塞获取结果(仅演示,实际少用)

        // 2. runAsync:无返回值的异步任务(比如模拟发送通知)
        CompletableFuture<Void> notifyFuture = CompletableFuture.runAsync(() -> {
            try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); }
            System.out.println("异步发送订单通知完成");
        });
        notifyFuture.get(); // 等待任务完成
    }
}

2. 核心:结果处理/转换

任务执行完成后,对结果进行转换、消费或异常处理(非阻塞回调)。

方法 作用 特点
thenApply(Function<T,U>) 转换结果(输入T,输出U) 有入参、有返回值
thenAccept(Consumer<T>) 消费结果(输入T) 有入参、无返回值
thenRun(Runnable) 任务完成后执行(无参数) 无入参、无返回值
whenComplete(BiConsumer<T,Throwable>) 处理结果+异常(不改变结果) 可捕获异常,返回原结果
exceptionally(Function<Throwable,T>) 异常兜底(返回默认值) 异常时触发,返回替代结果

示例代码(基于上面的priceFuture扩展):

java 复制代码
public static void main(String[] args) throws ExecutionException, InterruptedException {
    CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> {
        // 模拟异常场景:随机抛出异常
        if (Math.random() > 0.5) {
            throw new RuntimeException("查询价格失败");
        }
        return 99;
    });

    // 1. thenApply:转换结果(价格→价格+运费)
    CompletableFuture<Integer> totalPriceFuture = priceFuture.thenApply(price -> price + 10);

    // 2. whenComplete:处理结果+异常(仅打印,不改变结果)
    totalPriceFuture.whenComplete((totalPrice, ex) -> {
        if (ex != null) {
            System.out.println("处理价格失败:" + ex.getMessage());
        } else {
            System.out.println("最终总价:" + totalPrice);
        }
    });

    // 3. exceptionally:异常兜底(失败时返回默认价格)
    CompletableFuture<Integer> finalFuture = totalPriceFuture.exceptionally(ex -> 0);
    System.out.println("兜底后的价格:" + finalFuture.get());
}

3. 进阶:多任务组合

处理多个异步任务的依赖或并行关系,是CompletableFuture最强大的特性。

方法 作用 适用场景
thenCompose(Function<T,CompletableFuture<U>>) 串联依赖任务(任务B依赖任务A的结果) 先查订单→再查订单详情
thenCombine(CompletableFuture<U>, BiFunction<T,U,V>) 合并两个独立任务的结果 并行查商品价格和库存,合并结果
allOf(CompletableFuture<?>...) 等待所有任务完成(无返回值) 并行处理多个无依赖的任务(如批量更新)
anyOf(CompletableFuture<?>...) 等待任一任务完成(返回第一个完成的结果) 多渠道查询数据,取最快的那个

示例代码

java 复制代码
public static void main(String[] args) throws ExecutionException, InterruptedException {
    // 任务1:查询商品价格
    CompletableFuture<Integer> priceFuture = CompletableFuture.supplyAsync(() -> 99);
    // 任务2:查询商品库存(独立任务)
    CompletableFuture<Integer> stockFuture = CompletableFuture.supplyAsync(() -> 1000);

    // 1. thenCombine:合并两个独立任务的结果
    CompletableFuture<String> combineFuture = priceFuture.thenCombine(stockFuture, (price, stock) -> {
        return "商品价格:" + price + ",库存:" + stock;
    });
    System.out.println(combineFuture.get()); // 输出:商品价格:99,库存:1000

    // 2. thenCompose:串联依赖任务(先查价格→再算折扣价)
    CompletableFuture<Integer> discountFuture = priceFuture.thenCompose(price -> {
        // 第二个任务依赖第一个任务的结果
        return CompletableFuture.supplyAsync(() -> price * 9 / 10);
    });
    System.out.println("折扣价:" + discountFuture.get()); // 输出:折扣价:89

    // 3. allOf:等待所有任务完成(无返回值)
    CompletableFuture<Void> allFuture = CompletableFuture.allOf(priceFuture, stockFuture, discountFuture);
    allFuture.get(); // 等待所有任务完成
    System.out.println("所有任务执行完毕");

    // 4. anyOf:取第一个完成的任务结果
    CompletableFuture<String> fastFuture1 = CompletableFuture.supplyAsync(() -> {
        try { Thread.sleep(1000); } catch (InterruptedException e) {}
        return "渠道1结果";
    });
    CompletableFuture<String> fastFuture2 = CompletableFuture.supplyAsync(() -> {
        try { Thread.sleep(500); } catch (InterruptedException e) {}
        return "渠道2结果";
    });
    CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(fastFuture1, fastFuture2);
    System.out.println("最快的结果:" + anyFuture.get()); // 输出:渠道2结果
}

4. 结果获取:get() vs join()

这两个方法都用于获取异步任务结果,核心区别是异常处理

  • get():抛出InterruptedExceptionExecutionException(检查异常),必须捕获或声明抛出;
  • join():抛出非检查异常(CompletionException),无需捕获,更适合流式调用。

示例

java 复制代码
// get()需要捕获异常
try {
    Integer price = priceFuture.get();
} catch (InterruptedException | ExecutionException e) {
    e.printStackTrace();
}

// join()无需捕获异常(推荐在流式调用中使用)
Integer price = priceFuture.join();

二、关键注意事项

  1. 线程池supplyAsync/runAsync默认使用ForkJoinPool.commonPool(),如果任务耗时久/数量多,建议自定义线程池(避免占用公共线程池):

    java 复制代码
    // 自定义线程池
    ExecutorService executor = Executors.newFixedThreadPool(5);
    CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 99, executor);
  2. 异常处理 :务必通过whenComplete/exceptionally处理异常,否则异步任务的异常会被吞掉,难以排查;

  3. 避免阻塞 :尽量使用回调方法(thenApply/thenAccept等)替代get()/join()阻塞获取结果,发挥异步优势。

总结

  1. CompletableFuture核心分为4类方法:创建任务(supplyAsync/runAsync)、结果处理(thenApply/exceptionally)、任务组合(thenCompose/allOf)、结果获取(get/join)
  2. thenCompose用于串联依赖任务,thenCombine用于合并独立任务,allOf/anyOf用于多任务批量处理;
  3. 优先使用join()(非检查异常)和自定义线程池,同时做好异常兜底。
相关推荐
北鹿不麋鹿2 小时前
自学Java手记:Map集合,Arrays工具类和Lambda表达式
java
码头整点薯条2 小时前
对接第三方服务踩坑:属性大小写不匹配导致数据解析失败,一个注解搞定!
java
Wpa.wk2 小时前
性能测试工具 - JMeter工具组件介绍一
java·经验分享·测试工具·jmeter·性能测试
虫小宝2 小时前
个微iPad协议场景下Java后端的协议解析异常排查与问题定位技巧
java·svn·ipad
vyuvyucd2 小时前
Python虚拟环境终极指南:venv到uv进阶
开发语言·python·uv
程序媛徐师姐2 小时前
Java基于微信小程序的鲜花销售系统,附源码+文档说明
java·微信小程序·鲜花销售小程序·java鲜花销售小程序·鲜花销售微信小程序·java鲜花销售系统小程序·java鲜花销售微信小程序
Tim_102 小时前
【C++入门】05、复合类型-数组
开发语言·c++·算法
无限进步_2 小时前
【C语言&数据结构】另一棵树的子树:递归思维的双重奏
c语言·开发语言·数据结构·c++·算法·github·visual studio
佑白雪乐2 小时前
<Python第1集>
开发语言·python