CompletableFuture理解与使用

CompletableFuture是Java中用于异步编程的强大工具,它解决了传统线程和Future接口在处理返回值和线程间依赖时的局限性。CompletableFuture提供了多种方法,如thenApply、thenAccept、whenComplete等,用于构建复杂的异步流程,包括串行、并行和异常处理。此外,它还支持通过thenCompose进行组合操作,以及通过allOf和anyOf进行多个任务的聚合。使用CompletableFuture可以更高效地管理异步任务,尤其是在需要处理多个异步结果时。
摘要由CSDN通过智能技术生成

一. CompletableFuture的前世今生

在CompletableFuture出现之前我们先了解一下多线程任务场景的痛点, 根据Oracle官方出具的Java文档说明, 创建线程的方式只有两种, 继承Thread类或者实现Runnable接口。但是这两种方法都存在一个缺陷, 就是都没有返回值, 也就是说我们无法得知线程执行结果。
虽然简单场景下已经满足, 但是当我们需要返回值的时候怎么办呢?所以Java1.5以后有了Callable和Future接口来解决此问题,我们可以通过向线程池提交一个Callable来获取一个包含返回值的Future对象, 从此我们的程序就可以更多的方式来异步执行, 但Future获得线程的执行结果调用的get()方法会阻塞主线程,所以这是个非常耗时的操作,不仅如此,有时我们的一些业务场景需要有更强大的异步能力,比如,将两个异步计算合并为一个,这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果,又或者我们需要同时执行多个异步线程,任意一个执行完就可以继续进行下一步操作, 这时CompletableFuture就要登场了.

Tips:

  • CompletionStage 接口里面描述串行关系,主要是 thenApply、thenAccept、thenRun 和 thenCompose 这四个系列的接口
  • CompletionStage 接口里面描述 AND 汇聚关系,主要是 thenCombine、thenAcceptBoth 和 runAfterBoth 系列的接口
  • CompletionStage 接口里面描述 OR 汇聚关系,主要是 applyToEither、acceptEither 和 runAfterEither 系列的接口
  • CompletionStage 接口里面描述 Try-Catch关系,CompletionStage exceptionally(fn)
  • CompletionStage 接口里面描述 Try-Finally关系,主要有如下几种
    • CompletionStage whenComplete(consumer);
    • CompletionStage whenCompleteAsync(consumer);
    • CompletionStage handle(fn);
    • CompletionStage handleAsync(fn);

在这里插入图片描述

从图中我们可以看到CompletableFuture实现了Future与CompletionStage两个接口.

Future接口的核心功主要是用来表示异步计算结果,提供了检查计算是否完成,等待其完成,以及检索计算结果的方法.

CompletionStage接口的核心功能是用于线程异步执行中的阶段处理,其中定义了一组接口用于在一个阶段执行结束之后,要么继续执行下一个阶段,要么对结果进行转换产生新的结果等.

二. CompletableFuture Api使用

  • CompletableFuture 的方法中如不指定自定义的线程池,则默认使用的是Jvm 全局的Forkjoinpool.commonPool() 线程池, 这个线程池会被JDK 和我们常用的 SpringFramework / Springboot 等很多框架共用,所以建议指定自定义的线程池去执行服务中的业务操作

  • CompletableFuture的方法中所有以Async结尾的方法都是另起新的线程来执行任务的


1.任务实例化

public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);
public static CompletableFuture<Void> runAsync(Runnable runnable);
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);

在这里插入图片描述

  • runAsync()方法无返回值, 可以指定自定义线程池
  • supplyAsync()方法存在返回值, 可以指定自定义线程池

2.获取任务结果

public T get()
public T get(long timeout, TimeUnit unit)
public T getNow(T valueIfAbsent)
public T join()

在这里插入图片描述

  • get() 方法阻塞获取结果, 可指定超时时间, 抛出经过检查的异常, 强制开发者处理异常
  • getNow() 方法不会阻塞, 如果线程执行完成则返回结果, 未执行完成或内部出现异常则返回设置的默认值
  • join() 方法也是阻塞获取结果, 区别在于抛出未经检查的异常, 不会强制开发者处理异常

3.Complete中间操作

public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action) 
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T, ? super Throwable> action, Executor executor)

在这里插入图片描述

接收参数为上层返回值和一个Throwable异常对象

  • whenComplete() 方法为同步方法, 由主线程执行任务
  • whenCompleteAsync() 方法为异步方法, 可由默认线程池或指定自定义线程池执行任务

4.Handle中间操作

public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn)
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor)

在这里插入图片描述

接收参数为上层返回值和一个Throwable异常对象, 并可返回新对象

  • handle() 方法为同步方法, 由主线程执行
  • handleAsync() 方法为异步方法, 可由默认线程池或指定自定义线程池执行任务

complete()系列方法和handle()系列方法, 区别在于complete()的参数为BiConsumer而handle()为BiFunction,类似lambda中相关的函数式接口定义,此处handle()可以对线程内数据操作,转换等

5.Apply中间操作

public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

在这里插入图片描述

接收参数为上层返回值, 无异常参数

  • thenApply() 方法为同步方法, 由主线程执行
  • thenApplyAsync() 方法为异步方法, 可由默认线程池或指定自定义线程池执行任务

6.Accept中间操作

public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)

在这里插入图片描述

  • thenAccept() 方法为同步方法, 由主线程执行
  • thenAcceptAsync() 方法为异步方法, 可由默认线程池或指定自定义线程池执行任务
  • thenAcceptBoth() 方法为同步方法, 该方法的作用是,可与新创建的任务线程组合,并接收两个线程的结果后做相关操作
  • thenAcceptBothAsync() 方法为异步方法, 作用同上

7.Exceptionally异常捕获操作

public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);
public CompletableFuture<T> exceptionallyAsync(Function<Throwable, ? extends T> fn);
public CompletableFuture<T> exceptionallyAsync(Function<Throwable, ? extends T> fn, Executor executor);public CompletableFuture<T> exceptionallyCompose(Function<Throwable, ? extends CompletionStage<T>> fn);
public CompletableFuture<T> exceptionallyComposeAsync(Function<Throwable, ? extends CompletionStage<T>> fn);

在这里插入图片描述

  • exceptionally() 方法捕获链路上的异常,并返回默认值
  • exceptionallyAsync() 方法同上, 增加支持自定义线程池
  • exceptionallyCompose() 和 exceptionallyComposeAsync() 方法支持捕获异常后返回新的 CompletionStage 实例

8.Compose组合操作

public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);

public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn);

public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,Executor executor);

在这里插入图片描述

组合操作和apply操作有些类似, 区别在于组合操作接收上层返回的参数,而返回新的CompletionStage实例

  • thenCompose() 方法为同步阻塞方法, 由主线程执行
  • thenComposeAsync() 方法为异步方法, 支持自定义线程池

9.Combine合并操作

public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn, Executor executor);
    }

在这里插入图片描述

合并操作是将上层多个结果逐级合并, 并在合并方法中增加处理操作

  • thenCombine() 方法为同步阻塞方法, 由主线程执行
  • thenCombineAsync() 方法为异步方法, 支持自定义线程池

10.多个任务聚合后操作

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs);
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs);
  • allof() 方法可为多个异步任务提供聚合, 所有异步任务全部完成才继续进行后续操作, 注意该方法无返回值
  • anyOf() 方法可为多个异步任务提供聚合, 任意一个异步任务完成就继续进行后续操作, 该方法返回Object类型对象

文章以上内容只介绍了大部分常用的Api并做了简单总结和对比, 希望能在工作中对大家有所帮助, 如有错误欢迎大家参与评论指正, 共同探讨.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值