CompletionStage 接口详解

Java CompletionStage 接口详解

CompletionStage 是 Java 并发编程中用于表示异步计算阶段的接口,通常与 CompletableFuture 结合使用。它允许定义多个依赖阶段,当前一阶段完成时触发后续操作,支持链式异步任务编排。

1. 调用示例

CompletableFutureCompletableFuture 的实现,如下代码是 CompletableFuture 方法的典型调用示例。

示例代码

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 10);

future
    .thenApplyAsync(x -> x * 2)        // 异步转换:20
    .thenCombine(CompletableFuture.supplyAsync(() -> 5), (a, b) -> a + b) // 合并结果:25
    .thenAccept(result -> System.out.println("Result: " + result)) // 消费结果
    .exceptionally(ex -> {
        System.err.println("Error: " + ex.getMessage());
        return null;
    });

示例代码的流程图

sequenceDiagram participant A as supplyAsync(10) participant B as thenApplyAsync(x*2) participant C as supplyAsync(5) participant D as thenCombine(a+b) participant E as thenAccept(print) participant F as exceptionally A->>B: 触发异步计算 (10 → 20) par 并行执行 B-->>D: 结果20 C-->>D: 结果5 end D->>E: 合并结果25 E->>E: 若无异常,结束 Note over E,F: 若异常,跳转至 exceptionally 处理

2. 核心原理

CompletionStage 阶段的处理逻辑可通过如下形式定义:

  • Function:接收输入并返回结果,对应方法如 thenApply()
    stage.thenApply(x -> x * 2); // 对结果进行计算
    
  • Consumer:接收输入但不返回结果,对应方法如 thenAccept()
    stage.thenAccept(x -> System.out.println(x)); // 消费结果
    
  • Runnable:不接收输入也不返回结果,对应方法如 thenRun()
    stage.thenRun(() -> System.out.println("Done")); // 执行操作
    
  • Compose:通过 thenCompose() 将阶段的结果转换为另一个阶段,避免嵌套。
    stage.thenCompose(x -> createNewStage(x)); // 将结果展平为新阶段
    

阶段处理方法的表格对比

方法类型 功能描述 输入参数 返回值 示例方法
转换(Function) 处理结果并返回新值 T → R R thenApply(), thenCompose()
消费(Consumer) 处理结果但不返回 T → void void thenAccept()
动作(Runnable) 无输入无输出的操作 void void thenRun()
合并(Compose) 合并两个阶段的结果 T,U → V V thenCombine()
异常处理 处理正常/异常结果 (T, Throwable) - whenComplete(), handle()

CompletionStage 核心流程示意图

flowchart LR subgraph 触发条件 A[Stage1: 完成] -->|thenApply| B[Stage2: Function] A -->|thenAccept| C[Stage3: Consumer] A -->|thenRun| D[Stage4: Runnable] E[Stage5] & F[Stage6] -->|thenCombine| G[合并结果] E -->|applyToEither| H[取最先完成的结果] end subgraph 执行方式 B -->|默认执行| B_Sync[同步: 触发线程] B -->|Async后缀| B_Async[异步: ForkJoinPool] B -->|自定义Executor| B_Custom[指定线程池] end subgraph 异常处理 B -->|正常完成| B_Normal[传递结果] B -->|异常完成| B_Error[传播异常] B_Error -->|whenComplete| I[记录异常] B_Error -->|handle| J[返回替代结果] end classDef stage fill:#f9f,stroke:#333; classDef async fill:#6f9,stroke:#333; classDef error fill:#f96,stroke:#333; class A,B,C,D,E,F,G,H,I,J stage class B_Async,B_Custom async class B_Error,I,J error

3. 触发条件

阶段的触发方式取决于前置阶段的完成情况:

  • 单个阶段完成:使用 then 前缀方法,如 thenApply()
  • 两个阶段均完成:合并结果,如 thenCombine()
    stage1.thenCombine(stage2, (x, y) -> x + y); // 合并两个结果
    
  • 任一阶段完成:使用 applyToEither() 等方法,结果不确定。
    stage1.applyToEither(stage2, x -> x); // 取最先完成的结果
    

4. 执行方式

支持三种执行模式:

  • 默认执行:由触发阶段的线程同步执行。
  • 异步执行:通过 async 后缀方法(如 thenApplyAsync())提交到默认线程池(如 ForkJoinPool)。
  • 自定义执行器:显式指定 Executor,控制线程管理。
    stage.thenApplyAsync(x -> x * 2, customExecutor); // 使用自定义线程池
    

5. 异常处理

CompletionStage 的异常处理像一个「管道中的错误传递」——如果不主动处理,异常会一直传递到链的末端;而通过 handle/exceptionally 可以像「阀门」一样截断异常,替换为正常值继续流动。

  • whenComplete():无论正常或异常完成,均执行操作,但保留原结果。
    stage.whenComplete((result, ex) -> {
        if (ex != null) System.out.println("Error: " + ex);
    });
    
  • handle():可处理异常并返回替代结果,影响后续阶段。
    stage.handle((result, ex) -> ex != null ? 0 : result); // 异常时返回默认值
    
  • 异常传播:若阶段抛出异常,所有依赖它的阶段将以 CompletionException 包装异常完成。依赖多个阶段时,异常来源可能不确定。

异常处理方法表格对比

方法 作用 是否改变结果 示例
whenComplete 记录日志,但保留原结果/异常 ❌ 不改变 stage.whenComplete((res, ex) -> log(ex))
handle 处理异常并返回替代结果 ✔️ 改变 stage.handle((res, ex) -> ex != null ? 0 : res)
exceptionally 仅处理异常,返回默认值 ✔️ 改变 stage.exceptionally(ex -> 0)

6. 注意事项

  • 参数限制:除结果参数可为 null 外,其他参数非空,否则抛出 NullPointerException
  • 顺序不保证:依赖关系仅控制触发时机,不保证执行顺序。
  • 实现扩展:接口本身不提供创建或强制完成方法,需通过实现类(如 CompletableFuture)实现。

示例:链式调用与异常处理

CompletableFuture.supplyAsync(() -> fetchData())
    .thenApply(data -> process(data))
    .exceptionally(ex -> handleError(ex))
    .thenAccept(result -> save(result));

此链式调用中,supplyAsync 异步获取数据,thenApply 处理结果,exceptionally 处理异常并返回默认值,最后 thenAccept 保存结果。


总结

本文解释了 CompletionStage 的链式触发机制、异步执行策略及异常处理逻辑。其核心是通过函数式编程模型,将复杂的异步任务拆解为多个可组合的阶段,适合构建高并发、低延迟的应用。

posted @ 2025-03-25 23:41  皮皮是个不挑食的好孩子  阅读(117)  评论(0)    收藏  举报