CompletableFuture使用详解

Callable和Runnable的区别

@FunctionalInterface
public interface Runnable {
   
   
	//void方法没有返回值
    public abstract void run();
}

@FunctionalInterface
public interface Callable<V> {
   
   
	//有返回值,并且能抛出异常
    V call() throws Exception;
}

Future的主要功能

public interface Future<V> {
   
   
	/**
	方法说明:取消任务的执行。
	参数:MayInterruptFrunning–如果执行此任务的线程应该被中断,则为true;否则,允许完成正在进行的任务
  	返回值:如果无法取消任务(通常是因为任务已正常完成),则为false;反之亦然
  	*/
    boolean cancel(boolean mayInterruptIfRunning);
	
	/**
    方法说明:如果此任务在正常完成之前被取消,则返回true。
  	返回值:如果此任务在完成之前取消,则为true
  	*/
    boolean isCancelled();

	/**
    方法说明:如果此任务已完成,则返回true。完成可能是由于正常终止、异常或取消——在所有这些情况下,此方法将返回true。
    返回值:如果此任务已完成,则为true
    */
    boolean isDone();

	/**
	方法说明:如有必要,等待计算完成,然后检索其结果。
  	返回值:计算结果
  	抛出:ExecutionException–如果计算引发异常
	     InterruptedException–如果当前线程在等待时被中断
	     CancellationException-如果任务被取消
	*/
    V get() throws InterruptedException, ExecutionException;

	/**
	方法说明:如有必要,最多等待给定的时间以完成计算,然后检索其结果(如果可用)。
	参数:timeout–等待的最长时间
         unit–超时参数的时间单位
    返回:计算结果
	抛出:ExecutionException–如果计算引发异常
	     InterruptedException–如果当前线程在等待时被中断
	     TimeoutException–如果等待超时
	     CancellationException-如果任务被取消
	*/
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

利用 FutureTask 创建 Future

在这里插入图片描述
Future实际采用FutureTask实现,该对象相当于是消费者和生产者的桥梁,消费者通过 FutureTask 存储任务的处理结果,更新任务的状态:未开始、正在处理、已完成等。而生产者 拿到的 FutureTask 被转型为 Future 接口,可以阻塞式获取任务的处理结果,非阻塞式获取任 务处理状态。 FutureTask既可以被当做Runnable来执行,也可以被当做Future来获取Callable的返回结果。

使用案例:促销活动中商品信息查询
*在维护促销活动时需要查询商品信息(包括商品基本信息、商品价格、商品库存、商品图 片、商品销售状态等)。*这些信息分布在不同的业务中心,由不同的系统提供服务。如果采用同步方式,假设一个接口需要50ms,那么一个商品查询下来就需要200ms-300ms。如果使用Future改造则需要的就是最长耗时服务的接口,也就是50ms左 右。
在这里插入图片描述

   public static void main(String[] args) {
   
   

        //查询商品基本信息
        FutureTask<String> ft1 = new FutureTask<>(new T1Task());
        //查询商品促销价格
        FutureTask<String> ft2 = new FutureTask<>(new T2Task());
        //查询商品库存
        FutureTask<String> ft3 = new FutureTask<>(new T3Task());
        //查询商品图片
        FutureTask<String> ft4 = new FutureTask<>(new T4Task());
        //查询商品销售状态
        FutureTask<String> ft5 = new FutureTask<>(new T5Task());
        //线程池运行任务
        ScheduledExecutorService executor = SpringUtils.getBean("threadPoolTaskExecutor");
        executor.submit(ft1);
        executor.submit(ft2);
        executor.submit(ft3);
        executor.submit(ft4);
        executor.submit(ft5);
        //获取结果
        ft1.get();
        ft2.get();
        ft3.get();
        ft4.get();
        ft5.get();
        //关闭线程池
        executor.shutdown();

    }

Future的局限性

  • 并发执行多任务:Future只提供了get()方法来获取结果,并且是阻塞的。所以,除 了等待你别无他法;
  • 无法对多个任务进行链式调用:如果你希望在计算任务完成后执行特定动作,比如 发邮件,但Future却没有提供这样的能力;
  • 无法组合多个任务:如果你运行了10个任务,并期望在它们全部执行结束后执行特 定动作,那么在Future中这是无能为力的;
  • 没有异常处理:Future接口中没有关于异常处理的方法;

CompletionService
主要功能:
CompletionService的主要功能就是一 边生成任务,一边获取任务的返回值。让两件事分开执行,任务之间不会互相阻塞,可以实现先执 行完的先取结果,不再依赖任务顺序了。

原理:
内部通过阻塞队列+FutureTask,实现了任务先完成可优先获取到,即结果按照完成先后顺序排序,内部有一个先进先出的阻塞队列,用于保存已经执行完成的Future,通过调用它的 take方法或poll方法可以获取到一个已经执行完成的Future,进而通过调用Future接口实现类 的get方法获取最终的结果

使用案例:
询价应用:向不同电商平台询价,并保存价格

//获取线程池
ExecutorService executor = SpringUtils.getBean("xecutorService")
<think>嗯,用户想了解CompletableFuture的原理和详细实现,特别是Java异步编程方面的深入分析。首先,我需要回顾一下之前提供的引用内容,看看有哪些信息可以利用。引用[1]提到CompletableFutureJava 8引入的,用于异步编程,属于java.util.concurrent包,相比传统Future更灵活,支持链式调用、任务合并和异常处理。引用[2]强调了它的高效异步模式和并发编程的简洁性。引用[3]指出CompletableFuture有很多方法和内部类,需要分步分析。引用[4]提到了Java并发的发展,包括ForkJoin框架等。 用户的问题是关于原理和实现的详细解析,所以需要深入讨论内部机制,比如如何实现异步任务的管理、回调链的处理、线程池的使用,以及如何组合多个任务。可能还需要涉及CompletableFuture的状态机、依赖关系处理、异常传播机制等。 首先,CompletableFuture基于ForkJoinPool,这点应该在实现原理部分提到。然后,它的核心结构可能涉及到每个阶段(stage)作为一个节点,形成链表或栈结构来处理依赖。状态管理方面,可能用volatile变量来保存结果和状态变化,确保可见性。 另外,需要解释CompletableFuture如何通过thenApply、thenAccept等方法链式组合任务,这些方法如何注册回调,并在前一个阶段完成时触发后续操作。这里可能涉及CompletionStage接口的实现,以及各种不同类型的Completion子类,比如UniApply、BiApply等,处理不同的依赖情况。 异常处理也是一个重点,CompletableFuture如何捕获异常并传递给后续的exceptionally或handle方法。需要说明当某个阶段出现异常时,后续依赖的阶段如何被触发,并处理异常结果。 线程池的集成部分,用户可能想知道默认使用的线程池,以及如何自定义。比如,默认使用ForkJoinPool.commonPool(),但也可以指定自定义的Executor。在实现中,如何将任务提交到线程池,并在任务完成后执行回调。 还有,组合多个CompletableFuture的方法,如allOf、anyOf,这些是如何实现的,可能涉及内部计数器或条件判断,等待所有或任意一个Future完成。 另外,性能优化方面,CompletableFuture如何减少线程阻塞,通过非阻塞的回调机制提高效率。对比传统的Future.get(),CompletableFuture通过回调通知机制避免了阻塞等待。 可能用户还想了解与响应式编程的区别,或者与其他异步框架如RxJava的不同之处,但根据问题,重点应放在CompletableFuture本身的原理和实现细节上。 需要确保回答结构清晰,分点讲解核心原理、状态管理、依赖处理、线程池机制、组合任务和异常处理等部分。同时,结合代码示例说明,比如创建异步任务的方法,链式调用的例子,以及异常处理的示例。 最后,生成相关问题时要围绕用户可能的进一步疑问,比如与传统的Future对比、如何选择线程池、实际应用场景、性能优化方法、异常处理最佳实践,以及和响应式编程的结合等。</think># CompletableFuture原理与实现深度解析 ## 一、核心实现原理 CompletableFuture基于观察者模式构建异步任务链,内部采用$stage$链表结构管理任务依赖关系。每个阶段通过$UniCompletion$/$BiCompletion$等内部类实现回调注册,采用无锁CAS操作保证线程安全[^3]。 状态机实现包含三个关键变量: $$ \begin{cases} result & \text{存储计算结果/异常对象} \\ stack & \text{等待触发的回调函数栈} \\ nest & \text{防止递归调用计数器} \end{cases} $$ ## 二、任务执行流程 1. **异步启动**:通过`supplyAsync()`创建任务时,默认使用$ForkJoinPool.commonPool()$[^4] ```java CompletableFuture<String> cf = CompletableFuture.supplyAsync(() -> { // 异步任务逻辑 return "result"; }); ``` 2. **依赖传播**:每个`thenApply()`调用生成新的$UniApply$节点并压入前驱的栈顶 3. **完成触发**:当前任务完成后,通过`postComplete()`方法反向遍历栈节点触发后续操作 ## 三、线程池集成机制 | 配置方式 | 实现类 | 适用场景 | |-------------------|-------------------------|-----------------------| | 默认线程池 | ForkJoinPool.commonPool | CPU密集型任务 | | 自定义线程池 | ThreadPoolExecutor | IO密集型任务 | | 直接执行 | Runnable::run | 快速回调(同线程执行) | ## 四、组合任务实现 1. **AND聚合**:`allOf()`通过$BiRelay$合并多个future结果 2. **OR聚合**:`anyOf()`使用$AtomicReference$竞争设置首个完成结果 3. **嵌套组合**:`thenCompose()`通过$UniCompose$实现future级联 ## 五、异常处理机制 1. 异常传播路径:通过$AltResult$包装异常对象沿任务链传递 2. 恢复机制:`exceptionally()`注册的恢复函数可返回替代值 3. 全局捕获:`handle()`方法同时接收结果和异常参数 ```java CompletableFuture.supplyAsync(() -> { if (new Random().nextBoolean()) throw new RuntimeException("模拟异常"); return "data"; }).exceptionally(ex -> { System.out.println("捕获异常: " + ex.getMessage()); return "default"; }); ``` ## 六、性能优化设计 1. 延迟提交:使用$LazyExecutor$减少线程切换开销 2. 栈优化:采用Treiber栈结构提升并发压栈性能[^2] 3. 对象复用:内部$ASYNC$/$NIL$等标记对象减少内存分配
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VI仔爱学习

让我看看是谁在学习

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值