【Java源码阅读系列28】深度解读Java CompletableFuture 源码

Java 8 引入的 CompletableFuture 是并发编程中处理异步任务的核心工具,它通过实现 FutureCompletionStage 接口,提供了链式调用、任务组合、异常处理等强大功能。本文将结合源码,深入解析其核心机制、设计模式,并给出常见使用场景与代码示例。

一、核心架构:状态管理与依赖任务

CompletableFuture 的核心目标是将异步任务的完成状态与依赖操作解耦,允许通过链式调用定义任务完成后的行为(如计算、消费、异常处理等)。其内部通过以下关键字段实现状态管理和依赖触发:

1.1 状态与结果存储:result 字段

volatile Object result;       // 存储任务结果或异常(AltResult类型)
  • 正常结果:直接存储结果值(若为 null 则用 NIL包装)。
  • 异常结果:通过 AltResult 类包装异常(如 CompletionException)。
  • 原子性:通过 UNSAFE.compareAndSwapObject实现原子性状态更新(如 completeValuecompleteThrowable 方法)。

1.2 依赖任务栈:stack 字段

volatile Completion stack;    // Treiber 栈结构,存储依赖的Completion任务

stack 是一个无锁的 Treiber 栈,用于存储所有依赖当前任务的后续操作(如 thenApplythenAccept 等定义的任务)。每个依赖任务是 Completion 接口的实现类(如 UniApplyBiApply),通过 next 字段链接成栈。

1.3 任务触发:postComplete 方法

当当前任务完成(正常或异常)时,postComplete 方法会被调用,遍历 stack 栈并触发所有依赖任务:

final void postComplete() {
    CompletableFuture<?> f = this; Completion h;
    while ((h = f.stack) != null || (f != this && (h = (f = this).stack) != null)) {
        if (f.casStack(h, h.next)) {  // 原子弹出栈顶任务
            h.tryFire(NESTED);        // 触发任务执行
            f = (h.tryFire(NESTED) == null) ? this : h.dep;  // 递归处理依赖
        }
    }
}
  • 无锁遍历:通过 casStack 原子操作弹出栈顶任务,避免锁竞争。
  • 递归触发:每个 Completion 任务的 tryFire 方法执行后,可能触发其依赖任务的 postComplete,形成级联触发。

二、关键机制解析

2.1 异步任务执行策略

CompletableFuture 的异步方法(如 thenApplyAsync)默认使用 ForkJoinPool.commonPool() 执行任务,若并行度不足则回退到单线程:

private static final boolean useCommonPool = (ForkJoinPool.getCommonPoolParallelism() > 1);
private static final Executor asyncPool = useCommonPool ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

static class ThreadPerTaskExecutor implements Executor {
    public void execute(Runnable r) { new Thread(r).start(); }  // 单线程执行器
}
  • 策略选择:通过 useCommonPool 动态选择执行器,平衡资源利用率和任务并行度。
  • 扩展性:用户可通过传入自定义 Executor 覆盖默认策略(如 thenApplyAsync(fn, executor))。

2.2 依赖任务的类型与执行

CompletableFuture 支持多种依赖任务类型,通过内部类 UniCompletion(单输入)和 BiCompletion(双输入)实现:

2.2.1 单输入任务(UniCompletion

处理单个前置任务的完成事件,例如 thenApply

abstract static class UniCompletion<T,V> extends Completion {
    Executor executor;          // 任务执行器(可能为null)
    CompletableFuture<V> dep;   // 当前任务的依赖(即下一个阶段)
    CompletableFuture<T> src;   // 前置任务(当前阶段的源)

    final boolean claim() {     // 原子声明任务所有权(避免重复执行)
        if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
            if (executor == null) return true;  // 同步执行
            executor.execute(this);             // 异步执行
        }
        return false;
    }
}
  • 原子声明:通过 ForkJoinTasktag 字段原子标记任务是否已被认领,避免多线程重复执行。
  • 执行模式:若 executornull(同步模式),直接执行;否则异步提交到执行器。

2.2.2 双输入任务(BiCompletion

处理两个前置任务的完成事件,例如 thenCombine

abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
    CompletableFuture<U> snd;   // 第二个前置任务
}

双输入任务需要等待两个前置任务均完成(或任一完成,取决于具体方法),通过 CoCompletion 类协调两个前置任务的触发:

static final class CoCompletion extends Completion {
    BiCompletion<?,?,?> base;   // 指向基础双输入任务
    final CompletableFuture<?> tryFire(int mode) {
        return base.tryFire(mode);  // 委托给基础任务执行
    }
}

2.3 异常处理与传播

CompletableFuture 的异常处理通过 completeExceptionally 方法触发,异常会被包装为 CompletionException 并传播给依赖任务:

final boolean completeThrowable(Throwable x) {
    return UNSAFE.compareAndSwapObject(this, RESULT, null, encodeThrowable(x));
}

static AltResult encodeThrowable(Throwable x) {
    return new AltResult((x instanceof CompletionException) ? x : new CompletionException(x));
}
  • 异常传播:依赖任务(如 exceptionally)会检测到前置任务的异常结果,并执行相应的恢复逻辑。
  • 用户友好性get() 方法抛出 ExecutionException(兼容 Future 接口),而 join() 直接抛出 CompletionException(更简洁)。

三、设计模式深度解析

CompletableFuture 的源码中巧妙融合了多种设计模式,使其具备高度的灵活性和可扩展性。

3.1 观察者模式(Observer Pattern)

核心体现CompletableFuture 的依赖任务的注册与触发机制。

  • 主题(Subject):当前 CompletableFuture 实例(任务完成状态变化)。
  • 观察者(Observer):所有注册到 stack 中的 Completion 任务(依赖任务)。
  • 通知机制:任务完成时(postComplete)遍历观察者(stack 栈)并触发其 tryFire 方法。

示例:调用 thenApply(fn)时,会创建一个 UniApply 观察者并注册到当前任务的 stack 中。当前任务完成后,postComplete 触发 UniApply.tryFire,执行 fn 并完成依赖任务。

3.2 模板方法模式(Template Method Pattern)

核心体现Completion 及其子类的 tryFire 方法。

Completion 定义了模板方法 tryFire,子类(如 UniApplyBiApply)实现具体逻辑:

abstract static class Completion extends ForkJoinTask<Void> implements Runnable {
    abstract CompletableFuture<?> tryFire(int mode);  // 模板方法(核心逻辑)
    public final void run() { tryFire(ASYNC); }       // 固定流程(异步执行)
}

static final class UniApply<T,V> extends UniCompletion<T,V> {
    final CompletableFuture<V> tryFire(int mode) {  // 具体实现
        // 执行fn并完成依赖任务
    }
}
  • 模板方法tryFire 定义核心执行逻辑,子类(如 UniApplyUniAccept)实现具体行为。
  • 统一接口run() 方法统一异步执行入口,调用 tryFire(ASYNC)

3.3 策略模式(Strategy Pattern)

核心体现:异步任务的执行策略(Executor 接口)。

CompletableFuture 的异步方法(如 thenApplyAsync)默认使用 ForkJoinPool.commonPool(),用户可通过自定义 Executor 替换默认策略:

private static final Executor asyncPool = ...;  // 默认策略(ForkJoinPool或单线程)

public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) {
    return uniApplyStage(screenExecutor(executor), fn);  // 允许传入自定义Executor
}
  • 策略接口Executor 定义任务执行策略(execute(Runnable))。
  • 动态切换:用户可通过 thenApplyAsync(fn, executor) 传入自定义执行器(如 ThreadPoolExecutor),替换默认的 asyncPool,适应不同场景需求(如高并发、低延迟)。

3.4 责任链模式(Chain of Responsibility)

核心体现:链式调用(如 thenApply().thenAccept().exceptionally())通过 Completion 任务的级联触发实现责任链。

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello")
    .thenApply(s -> s + " world")       // 第一个Completion(UniApply)
    .thenAccept(s -> System.out.println(s))  // 第二个Completion(UniAccept)
    .exceptionally(e -> { /* 异常处理 */ });  // 第三个Completion(UniExceptionally)

每个 thenXxx 方法生成一个新的 CompletableFuture,并将其依赖任务(Completion)注册到前一个阶段的 stack 中。当前阶段完成后,触发下一个阶段的任务,形成链式调用。


四、关键方法源码解析

4.1 supplyAsync:异步任务提交

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
    return asyncSupplyStage(asyncPool, supplier);
}

private static <U> CompletableFuture<U> asyncSupplyStage(Executor e, Supplier<U> f) {
    CompletableFuture<U> d = new CompletableFuture<U>();
    e.execute(new AsyncSupply<U>(d, f));  // 提交任务到执行器
    return d;
}

static final class AsyncSupply<T> extends ForkJoinTask<Void> implements Runnable {
    CompletableFuture<T> dep;
    Supplier<T> fn;
    public void run() {
        if (dep.result == null) {  // 避免重复执行
            try {
                dep.completeValue(fn.get());  // 执行Supplier并设置结果
            } catch (Throwable ex) {
                dep.completeThrowable(ex);    // 异常处理
            }
        }
    }
}
  • 异步执行:通过 Executor 提交 AsyncSupply 任务,执行 Supplier 并设置结果。
  • 原子性:通过 dep.result == null 检查避免重复执行(如任务已被取消)。

4.2 thenApply:任务转换

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
    return uniApplyStage(null, fn);  // 同步模式(无Executor)
}

private <V> CompletableFuture<V> uniApplyStage(Executor e, Function<? super T,? extends V> f) {
    CompletableFuture<V> d = new CompletableFuture<V>();
    if (e != null || !d.uniApply(this, f, null)) {  // 若需异步或当前任务未完成
        UniApply<T,V> c = new UniApply<>(e, d, this, f);  // 创建UniApply任务
        push(c);  // 注册到当前任务的stack中
        c.tryFire(SYNC);  // 尝试同步触发(若当前任务已完成)
    }
    return d;
}
  • 同步触发:若当前任务已完成(this.result != null),直接执行 fn 并完成依赖任务 d
  • 异步注册:若当前任务未完成,将 UniApply 任务注册到 this.stack 中,等待当前任务完成后触发。

五、常见使用场景与代码示例

CompletableFuture 广泛应用于异步计算、多任务组合、异常处理等场景,以下是典型示例:

3.1 异步任务提交与链式处理

场景:异步获取数据并处理。

import java.util.concurrent.CompletableFuture;

public class AsyncDemo {
    public static void main(String[] args) {
        // 异步获取用户ID
        CompletableFuture<Integer> userIdFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(100);  // 模拟耗时操作
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return 1001;
        });

        // 链式处理:根据用户ID获取用户名
        CompletableFuture<String> userNameFuture = userIdFuture
            .thenApply(userId -> "User-" + userId)
            .exceptionally(e -> {  // 异常处理
                System.err.println("Error: " + e.getMessage());
                return "Unknown";
            });

        // 阻塞等待结果
        System.out.println("Username: " + userNameFuture.join());  // 输出:User-1001
    }
}

3.2 多任务组合(allOf/anyOf

场景:等待多个任务完成(allOf)或任一任务完成(anyOf)。

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

public class CombineTasksDemo {
    public static void main(String[] args) {
        // 任务1:查询订单
        CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Order-202310";
        });

        // 任务2:查询物流
        CompletableFuture<String> logisticsFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(150);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
            return "Delivered";
        });

        // 等待所有任务完成
        CompletableFuture<Void> allTasks = CompletableFuture.allOf(orderFuture, logisticsFuture);
        allTasks.join();

        System.out.println("Order: " + orderFuture.join());       // 输出:Order-202310
        System.out.println("Logistics: " + logisticsFuture.join());  // 输出:Delivered

        // 等待任一任务完成(示例:anyOf)
        CompletableFuture<Object> anyTask = CompletableFuture.anyOf(orderFuture, logisticsFuture);
        Object result = anyTask.get(200, TimeUnit.MILLISECONDS);  // 物流任务先完成
        System.out.println("First completed: " + result);  // 输出:Delivered
    }
}

3.3 异常处理与恢复

场景:任务执行失败时,使用默认值或备用逻辑恢复。

import java.util.concurrent.CompletableFuture;

public class ExceptionHandlingDemo {
    public static void main(String[] args) {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException("Simulated error");  // 模拟异常
        }).exceptionally(e -> {  // 异常处理
            System.err.println("Recovering from error: " + e.getMessage());
            return 0;  // 默认值
        });

        System.out.println("Result: " + future.join());  // 输出:Result: 0
    }
}

六、总结

CompletableFuture 通过无锁状态管理(resultstack)、依赖任务的级联触发(postComplete)和灵活的异步策略(Executor),实现了强大的异步编程能力。其设计融合了观察者模式(依赖触发)、模板方法模式(任务执行流程)、策略模式(异步执行器)和责任链模式(链式调用),是并发编程中“组合优于继承”“依赖倒置”等设计原则的典范。深入理解其源码,对优化异步任务设计、定位并发问题及掌握现代Java并发编程至关重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值