异步线程深度剖析(CompletableFuture/异步模式/虚拟线程)

异步线程深度剖析(CompletableFuture/异步模式/虚拟线程)

一、CompletableFuture 源码深度解析

1.1 核心数据结构

java 复制代码
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
    
    /**
     * 结果字段 - volatile 保证可见性
     * 
     * 状态:
     * - null: 未完成
     * - NIL: 完成但无结果(用于 CompletableFuture<Void>)
     * - AltResult: 完成但有异常
     * - 其他: 正常结果
     */
    volatile Object result;
    
    /**
     * 依赖的 Completion 栈
     * 
     * 结构:单向链表
     * 每个 Completion 代表一个依赖任务
     * 
     * 类型:
     * - UniCompletion: 单依赖(thenApply、thenAccept)
     * - BiCompletion: 双依赖(thenCombine、thenAcceptBoth)
     * - Signaller: 终结操作(whenComplete、handle、exceptionally)
     */
    volatile Completion stack;
    
    // NIL 对象(表示完成但无结果)
    static final Object NIL = new Object();
    
    // 内部类:异常结果包装
    static final class AltResult {
        final Throwable ex;
        AltResult(Throwable ex) { this.ex = ex; }
    }
}

1.2 Completion 栈结构

java 复制代码
    /**
     * Completion 基类
     * 
     * 设计思想:
     * 1. 使用栈(LIFO)而不是队列
     * 2. 每个 Completion 包含:依赖的 Future + 执行动作
     * 3. 完成时遍历栈,触发所有依赖
     */
    static abstract class Completion {
        Completion next;  // 指向下一个依赖(栈结构)
        
        /**
         * 尝试触发
         * @return true 表示已触发,false 表示等待其他依赖
         */
        abstract boolean tryFire(int mode);
        
        /**
         * 是否可触发
         */
        abstract boolean isDone();
    }
    
    /**
     * 单依赖 Completion
     * 
     * 用于:thenApply、thenAccept、thenRun
     */
    static final class UniCompletion extends Completion {
        Executor executor;      // 执行器
        CompletableFuture<?> dep;  // 依赖的 Future
        CompletableFuture<?> src;  // 源 Future
        
        UniCompletion(Executor e, CompletableFuture<?> dep, CompletableFuture<?> src) {
            this.executor = e;
            this.dep = dep;
            this.src = src;
        }
    }
    
    /**
     * UniApply - thenApply 的实现
     */
    static final class UniApply<T> extends UniCompletion {
        Function<Object, ? extends T> fn;
        
        UniApply(Executor e, CompletableFuture<T> dep, CompletableFuture<?> src,
                 Function<Object, ? extends T> fn) {
            super(e, dep, src);
            this.fn = fn;
        }
        
        @Override
        final boolean tryFire(int mode) {
            CompletableFuture<T> d; CompletableFuture<?> a;
            
            // 检查是否可以触发
            if ((d = dep) == null || !d.uniApply(a = src, fn, mode > 0))
                return false;
            
            // 触发后清理
            dep = null; src = null; fn = null;
            return true;
        }
    }

1.3 complete 方法源码

java 复制代码
    /**
     * 完成 Future
     * 
     * @param value 结果值
     * @return true 表示成功完成,false 表示已完成
     */
    public boolean complete(T value) {
        // 1. 设置结果
        boolean triggered = completeValue(value);
        
        // 2. 触发所有依赖
        postComplete();
        
        return triggered;
    }
    
    /**
     * 设置结果值
     */
    private boolean completeValue(Object value) {
        // CAS 设置结果
        // 如果 result 已经是非 null,说明已完成
        return UNSAFE.compareAndSwapObject(this, RESULT, null,
            value == null ? NIL : value);
    }
    
    /**
     * 触发所有依赖任务
     * 
     * 核心逻辑:
     * 1. 遍历 Completion 栈
     * 2. 对每个 Completion 调用 tryFire
     * 3. 如果 tryFire 返回 true,说明已触发
     * 4. 如果返回 false,说明需要等待其他依赖
     */
    final void postComplete() {
        for (Completion t = stack; t != null; ) {
            Completion next = t.next;
            
            // 尝试触发
            if (!t.tryFire(0)) {
                // 未触发,可能是异步执行
                // 将 t 加入执行队列
                if (t instanceof UniCompletion) {
                    UniCompletion u = (UniCompletion) t;
                    if (u.executor != null) {
                        u.executor.execute(() -> u.tryFire(1));
                    }
                }
            }
            
            t = next;
        }
    }

1.4 thenApply 源码

java 复制代码
    /**
     * 同步转换结果
     * 
     * @param fn 转换函数
     * @return 新的 CompletableFuture
     */
    public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn) {
        return uniApplyStage(null, fn);
    }
    
    /**
     * thenApply 核心实现
     */
    private <U> CompletableFuture<U> uniApplyStage(Executor e,
            Function<? super T, ? extends U> fn) {
        if (fn == null) throw new NullPointerException();
        
        CompletableFuture<U> d = new CompletableFuture<U>();
        
        // 检查是否已完成
        if (e != null || !d.uniApply(this, fn, null)) {
            // 未完成或需要异步执行
            // 创建 UniApply Completion 加入栈
            UniApply<T> c = new UniApply<T>(e, d, this, fn);
            pushCompletion(c);
        }
        
        return d;
    }
    
    /**
     * 执行 uni 转换
     * 
     * @param mode 0=同步,>0=异步,<0=检查
     */
    final <U> boolean uniApply(CompletableFuture<?> a,
            Function<Object, ? extends U> f, int mode) {
        Object r;
        
        // 检查源 Future 是否完成
        if ((r = a.result) == null)
            return false;  // 未完成
        
        // 检查是否有异常
        if (r instanceof AltResult) {
            Throwable ex = ((AltResult) r).ex;
            if (ex != null) {
                // 传播异常
                completeExceptionally(ex);
                return true;
            }
        }
        
        // 执行转换函数
        try {
            @SuppressWarnings("unchecked")
            T value = (T) (r == NIL ? null : r);
            U result = f.apply(value);
            complete(result);
        } catch (Throwable ex) {
            completeExceptionally(ex);
        }
        
        return true;
    }

二、异步编程模式

2.1 回调模式

java 复制代码
// 回调模式(Callback)
public class CallbackPattern {
    
    // 定义回调接口
    interface Callback<T> {
        void onSuccess(T result);
        void onFailure(Throwable error);
    }
    
    // 异步方法
    public void getUserAsync(Long userId, Callback<User> callback) {
        CompletableFuture.supplyAsync(() -> {
            // 模拟耗时操作
            return userService.getUser(userId);
        }).whenComplete((result, error) -> {
            if (error != null) {
                callback.onFailure(error);
            } else {
                callback.onSuccess(result);
            }
        });
    }
    
    // 使用
    public void example() {
        getUserAsync(1L, new Callback<User>() {
            @Override
            public void onSuccess(User result) {
                System.out.println("用户: " + result.getName());
            }
            @Override
            public void onFailure(Throwable error) {
                System.out.println("失败: " + error.getMessage());
            }
        });
    }
}

2.2 Future 模式

java 复制代码
// Future 模式
public class FuturePattern {
    
    public void example() {
        // 提交异步任务
        Future<User> future = executor.submit(() -> {
            return userService.getUser(1L);
        });
        
        // 做其他事情...
        doOtherWork();
        
        // 获取结果(阻塞)
        try {
            User user = future.get(5, TimeUnit.SECONDS);
        } catch (TimeoutException e) {
            // 超时处理
            future.cancel(true);
        }
    }
}

2.3 Promise 模式

java 复制代码
// Promise 模式(CompletableFuture 实现)
public class PromisePattern {
    
    public CompletableFuture<User> getUserPromise(Long userId) {
        CompletableFuture<User> promise = new CompletableFuture<>();
        
        executor.submit(() -> {
            try {
                User user = userService.getUser(userId);
                promise.complete(user);  // 完成 Promise
            } catch (Exception e) {
                promise.completeExceptionally(e);  // 异常完成
            }
        });
        
        return promise;
    }
    
    // 链式调用
    public CompletableFuture<Order> createOrder(Long userId) {
        return getUserPromise(userId)
            .thenApply(user -> {
                // 用户信息获取后,创建订单
                return orderService.create(user);
            })
            .thenApply(order -> {
                // 订单创建后,发送通知
                notificationService.send(order);
                return order;
            });
    }
}

三、异步编排实战

3.1 并行任务编排

java 复制代码
/**
 * 商品详情页 - 并行获取多个数据源
 */
public CompletableFuture<ProductDetailVO> getProductDetail(Long productId) {
    
    // 1. 并行获取基础数据
    CompletableFuture<Product> productFuture = 
        CompletableFuture.supplyAsync(() -> productService.getById(productId));
    
    CompletableFuture<List<Comment>> commentsFuture = 
        CompletableFuture.supplyAsync(() -> commentService.list(productId));
    
    CompletableFuture<Stock> stockFuture = 
        CompletableFuture.supplyAsync(() -> stockService.get(productId));
    
    CompletableFuture<Recommendation> recommendFuture = 
        CompletableFuture.supplyAsync(() -> recommendService.get(productId));
    
    // 2. 等待所有完成
    CompletableFuture<Void> allDone = CompletableFuture.allOf(
        productFuture, commentsFuture, stockFuture, recommendFuture
    );
    
    // 3. 组合结果
    return allDone.thenApply(v -> {
        ProductDetailVO vo = new ProductDetailVO();
        vo.setProduct(productFuture.join());
        vo.setComments(commentsFuture.join());
        vo.setStock(stockFuture.join());
        vo.setRecommendation(recommendFuture.join());
        return vo;
    });
}

/**
 * 带超时的并行获取
 */
public CompletableFuture<ProductDetailVO> getProductDetailWithTimeout(Long productId) {
    
    CompletableFuture<ProductDetailVO> future = getProductDetail(productId);
    
    // 设置超时
    return future.orTimeout(3, TimeUnit.SECONDS)
        .exceptionally(e -> {
            if (e instanceof TimeoutException) {
                log.warn("获取商品详情超时");
                return ProductDetailVO.defaultVO();
            }
            throw new CompletionException(e);
        });
}

3.2 串行 + 并行混合编排

java 复制代码
/**
 * 下单流程:串行 + 并行
 * 
 * 流程:
 * 1. 校验库存(串行)
 * 2. 计算优惠 + 计算运费(并行)
 * 3. 创建订单(串行)
 * 4. 扣减库存 + 发送通知(并行)
 */
public CompletableFuture<Order> createOrder(OrderRequest request) {
    
    // 1. 校验库存
    return stockService.check(request.getProductId(), request.getQuantity())
        .thenCompose(stock -> {
            // 2. 并行:计算优惠 + 计算运费
            CompletableFuture<Discount> discountFuture = 
                discountService.calculate(request);
            CompletableFuture<Freight> freightFuture = 
                freightService.calculate(request);
            
            return discountFuture.thenCombine(freightFuture, (discount, freight) -> {
                // 3. 创建订单
                return orderService.create(request, discount, freight);
            });
        })
        .thenCompose(order -> {
            // 4. 并行:扣减库存 + 发送通知
            CompletableFuture<Void> stockFuture = 
                stockService.deduct(order).thenApply(v -> null);
            CompletableFuture<Void> notifyFuture = 
                notificationService.send(order).thenApply(v -> null);
            
            return stockFuture.thenCombine(notifyFuture, (v1, v2) -> order);
        });
}

3.3 异常处理

java 复制代码
/**
 * 异常处理最佳实践
 */
public CompletableFuture<User> getUserWithFallback(Long userId) {
    
    return CompletableFuture.supplyAsync(() -> {
        return userService.getUser(userId);
    })
    // 捕获特定异常
    .exceptionally(e -> {
        if (e.getCause() instanceof TimeoutException) {
            log.warn("获取用户超时,使用缓存");
            return cacheService.getUser(userId);
        }
        throw new CompletionException(e);
    })
    // 统一异常处理
    .handle((result, error) -> {
        if (error != null) {
            log.error("获取用户失败", error);
            return User.defaultUser();
        }
        return result;
    });
}

四、虚拟线程(Virtual Threads)

4.1 虚拟线程原理

yaml 复制代码
虚拟线程 vs 平台线程:
┌─────────────────────────────────────────────────────────────┐
│  平台线程(Platform Thread)                                 │
│  ├── 1:1 映射到操作系统线程                                  │
│  ├── 创建成本高(~1MB 栈空间)                              │
│  ├── 数量受限(通常 < 1000)                                 │
│  └── 阻塞时占用 OS 线程                                     │
├─────────────────────────────────────────────────────────────┤
│  虚拟线程(Virtual Thread)                                  │
│  ├── M:N 映射(多个虚拟线程复用少量载体线程)                │
│  ├── 创建成本低(~几 KB)                                    │
│  ├── 数量可达百万级                                          │
│  └── 阻塞时自动切换载体线程                                  │
└─────────────────────────────────────────────────────────────┘

虚拟线程调度:
┌─────────────────────────────────────────────────────────────┐
│  虚拟线程 T1 执行                                            │
│  ├── 执行同步代码 → 在载体线程 C1 上运行                     │
│  ├── 遇到阻塞(IO/锁)→ 从 C1 卸载,保存状态               │
│  ├── 载体线程 C1 执行其他虚拟线程 T2                         │
│  ├── T1 阻塞结束 → 加入调度队列                              │
│  └── 载体线程 C1/C2 从队列取出 T1 继续执行                   │
└─────────────────────────────────────────────────────────────┘

4.2 虚拟线程使用

java 复制代码
// JDK 21+ 虚拟线程
public class VirtualThreadDemo {
    
    // 创建虚拟线程
    public void createVirtualThread() {
        Thread.startVirtualThread(() -> {
            System.out.println("Hello from virtual thread!");
            System.out.println("Thread: " + Thread.currentThread());
        });
    }
    
    // 使用 ExecutorService
    public void executorDemo() {
        // 创建虚拟线程执行器
        try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
            
            // 提交 100 万个任务
            for (int i = 0; i < 1_000_000; i++) {
                executor.submit(() -> {
                    // 模拟 IO 操作
                    Thread.sleep(Duration.ofSeconds(1));
                    return "done";
                });
            }
        }
        // 所有任务完成后关闭
    }
    
    // 虚拟线程 + CompletableFuture
    public CompletableFuture<String> asyncWithVirtualThread() {
        return CompletableFuture.supplyAsync(() -> {
            // 这段代码会在虚拟线程中执行
            return fetchData();
        }, Executors.newVirtualThreadPerTaskExecutor());
    }
}

4.3 虚拟线程 vs 协程

bash 复制代码
虚拟线程 vs 协程对比:
┌─────────────┬────────────────┬────────────────┐
│ 特性         │ 虚拟线程        │ 协程(Kotlin)  │
├─────────────┼────────────────┼────────────────┤
│ 语言支持     │ Java 原生       │ Kotlin 标准库   │
│ 语法         │ 普通线程 API    │ suspend/async  │
│ 调度         │ JVM 调度        │ 编译器 + 运行时 │
│ 阻塞兼容     │ 支持            │ 不支持(需转换)│
│ 性能         │ 接近协程        │ 略优            │
│ 学习成本     │ 低              │ 中              │
└─────────────┴────────────────┴────────────────┘

选择建议:
├── Java 项目:虚拟线程(无需改代码风格)
├── Kotlin 项目:协程(语法更优雅)
└── 高并发 IO:两者性能接近

五、异步编程最佳实践

5.1 线程池配置

java 复制代码
// 异步任务线程池配置
@Configuration
public class AsyncConfig {
    
    @Bean("asyncExecutor")
    public Executor asyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        
        // 核心参数
        executor.setCorePoolSize(20);      // CPU 核数 * 2
        executor.setMaxPoolSize(100);      // 根据任务量调整
        executor.setQueueCapacity(1000);   // 队列大小
        executor.setKeepAliveSeconds(60);  // 空闲超时
        
        // 线程命名
        executor.setThreadNamePrefix("async-");
        
        // 拒绝策略
        executor.setRejectedExecutionHandler((r, e) -> {
            log.warn("异步任务被拒绝: {}", r);
            // 降级:由调用线程执行
            r.run();
        });
        
        // 优雅关闭
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setAwaitTerminationSeconds(60);
        
        executor.initialize();
        return executor;
    }
}

// 使用
@Service
public class AsyncService {
    
    @Async("asyncExecutor")
    public CompletableFuture<User> getUserAsync(Long userId) {
        return CompletableFuture.completedFuture(
            userService.getUser(userId)
        );
    }
}

5.2 避免的陷阱

java 复制代码
// 陷阱1:阻塞虚拟线程
// 错误:在虚拟线程中使用 synchronized
synchronized (lock) {
    // 虚拟线程被阻塞,载体线程也被占用
    doBlockingIO();
}

// 正确:使用 ReentrantLock
lock.lock();
try {
    doBlockingIO();
} finally {
    lock.unlock();
}

// 陷阱2:CompletableFuture 链式阻塞
future.thenApply(r1 -> {
    // 这里会阻塞当前线程
    return blockingCall();  // 错误!
}).thenApply(r2 -> ...);

// 正确:使用 thenCompose
future.thenCompose(r1 -> {
    return CompletableFuture.supplyAsync(() -> blockingCall());
}).thenApply(r2 -> ...);

// 陷阱3:忘记处理异常
future.thenApply(r -> process(r));
// 如果 future 异常,这里不会执行,异常被吞掉

// 正确:处理异常
future.thenApply(r -> process(r))
      .exceptionally(e -> {
          log.error("处理失败", e);
          return defaultValue();
      });

六、面试题精选

Q1:CompletableFuture 的原理?

基于 Completion 栈,完成时遍历栈触发所有依赖任务


Q2:CompletableFuture 如何并行?

allOf 等待所有,anyOf 等待任一,thenCombine 组合结果


Q3:虚拟线程和平台线程的区别?

虚拟线程 M:N 映射,创建成本低,数量可达百万级


Q4:虚拟线程阻塞时会发生什么?

从载体线程卸载,保存状态,阻塞结束后加入调度队列


Q5:异步编程如何避免回调地狱?

使用 CompletableFuture 链式调用


Q6:@Async 的原理?

Spring AOP 代理,将方法调用提交到线程池


Q7:异步任务如何设置超时?

orTimeout 或 get(timeout)


Q8:异步任务异常如何处理?

exceptionally 捕获,handle 统一处理


Q9:虚拟线程适合什么场景?

IO 密集型(HTTP 调用、数据库查询、文件读写)


Q10:异步线程池如何配置?

根据任务类型设置核心线程数、队列大小、拒绝策略

相关推荐
苏三说技术1 小时前
推荐一个比ES快5倍的搜索引擎
后端
二月龙1 小时前
Java 线程池核心参数详解:从原理到生产避坑
后端
小强19881 小时前
线上 Java 项目 CPU 飙升、OOM 排查思路:完整实战流程
后端
学编程就要猛1 小时前
流式编程及Spring中SSE实现
java·后端·spring·流式编程
wechatbot8881 小时前
SpringBoot Vue 企业微信多账号托管|扫码登录 代理 IP 消息回调
大数据·后端·微信·企业微信·ai编程
不才不才不不才2 小时前
Spring 源码系列(27): @Transactional 七大失效场景与源码归因
java·后端·spring
妙码生花2 小时前
PHP 各框架下和 Go 的性能比较
前端·后端·go
名字还没想好☜2 小时前
Python 字符编码实战:encode/decode、UnicodeDecodeError 与 open 的 encoding 坑
开发语言·后端·python·编程语言
大勇前进2 小时前
Java 线程创建的 4 种方式,优缺点对比,开发推荐写法
后端