Java8 CompletableFuture 总结

Posted 小兵

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java8 CompletableFuture 总结相关的知识,希望对你有一定的参考价值。

原文链接:https://fxbing.github.io/2019...


CompletableFuture 是Java8 中新增的用来进行函数式异步编程的工具类。

最近学习源码的过程中看到有很多 CompletableFuture 的使用,感觉自己对这个类中的各个方法的使用场景和方法不是很熟悉,遂参考了下面几篇博客进行学习(本文大部分内容也都来自下面几篇博客):

Java CompletableFuture 详解

Java8新的异步编程方式 CompletableFuture(一)

Java8新的异步编程方式 CompletableFuture(二)

Java8新的异步编程方式 CompletableFuture(三)

上面的博客介绍的比较详细,为了自己查阅回看的方便,这里对这些方法进行一下总结(这里只总结不举例,具体使用需要看上面的博客)。

Future接口

Feture 接口包含五个方法,介绍如下:

  • boolean cancel (boolean mayInterruptIfRunning) 取消任务的执行。参数指定是否立即中断任务执行,或者等等任务结束
  • boolean isCancelled () 任务是否已经取消,任务正常完成前将其取消,则返回 true
  • boolean isDone () 任务是否已经完成。需要注意的是如果任务正常终止、异常或取消,都将返回true
  • V get () throws InterruptedException, ExecutionException 等待任务执行结束,然后获得V类型的结果。InterruptedException 线程被中断异常, ExecutionException任务执行异常,如果任务被取消,还会抛出CancellationException
  • V get (long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException 同上面的get功能一样,多了设置超时时间。参数timeout指定超时时间,uint指定时间的单位,在枚举类TimeUnit中有相关的定义。如果计 算超时,将抛出TimeoutException

主动完成计算

CompletableFuture实现了CompletionStageFuture两个接口。

通过阻塞或者轮询获得结果

方法名描述
public T get()Future接口实现
public T get(long timeout, TimeUnit unit)Future接口实现
public T getNow(T valueIfAbsent)如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值。
public T join()返回计算的结果或者抛出一个unchecked异常(CompletionException)
join()get()的区别是,join()只会抛出未检查异常(不需要使用try...catch..进行处理),而get()会抛出检查异常。

异步获取结果

  • 下面两个函数的调用会立即执行,并且只能执行一次。
  • 如果该任务已经执行完成,那么下面两个调用会无效,只能获取执行完成的结果。其实就是使任务立即结束(返回指定结果或者指定抛出异常)。
  • 比较适合需要返回CompletableFuture的方法,先创建一个空的CompletableFuture,之后通过下面两个函数指定前面创建的CompletableFuture的返回值。
方法名描述
complete(T t)完成异步执行,并返回future的结果
completeExceptionally(Throwable ex)异步执行不正常的结束

静态工厂方法

run 和 supply 的主要区别是异步操作是否有返回值(下面列出的所有方法也基本都是按照是否有返回值分为两类)。
方法名描述
runAsync(Runnable runnable)使用ForkJoinPool.commonPool()作为它的线程池执行异步代码。
runAsync(Runnable runnable, Executor executor)使用指定的thread pool执行异步代码。
supplyAsync(Supplier<U> supplier)使用ForkJoinPool.commonPool()作为它的线程池执行异步代码,异步操作有返回值。
supplyAsync(Supplier<U> supplier, Executor executor)使用指定的thread pool执行异步代码,异步操作有返回值。

下面几乎所有的方法都是一式三份,三种方法的区别是

  • 直接在当前线程执行
  • 换另一个线程(但是不指定线程)异步执行
  • 指定线程执行

转换

相当于 map 操作
方法名描述
thenApply(Function<? super T,? extends U> fn)接受一个Function<? super T,? extends U>参数用来转换CompletableFuture
thenApplyAsync(Function<? super T,? extends U> fn)接受一个Function<? super T,? extends U>参数用来转换CompletableFuture,使用ForkJoinPool
thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)接受一个Function<? super T,? extends U>参数用来转换CompletableFuture,使用指定的线程池
相当于 flatMap 操作
方法名描述
thenCompose(Function<? super T, ? extends CompletionStage<U>> fn)在异步操作完成的时候对异步操作的结果进行一些操作,并且仍然返回CompletableFuture类型。
thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn)在异步操作完成的时候对异步操作的结果进行一些操作,并且仍然返回CompletableFuture类型。使用ForkJoinPool。
thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn,Executor executor)在异步操作完成的时候对异步操作的结果进行一些操作,并且仍然返回CompletableFuture类型。使用指定的线程池。

组合

方法名描述
thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)当两个CompletableFuture都正常完成后,执行提供的fn,用它来组合另外一个CompletableFuture的结果。
thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)当两个CompletableFuture都正常完成后,执行提供的fn,用它来组合另外一个CompletableFuture的结果。使用ForkJoinPool。
thenCombineAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn, Executor executor)当两个CompletableFuture都正常完成后,执行提供的fn,用它来组合另外一个CompletableFuture的结果。使用指定的线程池。
thenAcceptBoth跟thenCombine类似,但是返回CompletableFuture类型。
方法名描述
thenAcceptBoth(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> action)当两个CompletableFuture都正常完成后,执行提供的action,用它来组合另外一个CompletableFuture的结果。
thenAcceptBothAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> action)当两个CompletableFuture都正常完成后,执行提供的action,用它来组合另外一个CompletableFuture的结果。使用ForkJoinPool。
thenAcceptBothAsync(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> action, Executor executor)当两个CompletableFuture都正常完成后,执行提供的action,用它来组合另外一个CompletableFuture的结果。使用指定的线程池。

计算结果完成时的处理

  • Action的类型是BiConsumer<? super T,? super Throwable>,它可以处理正常的计算结果,或者异常情况。
  • 方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其它的线程去执行(如果使用相同的线程池,也可能会被同一个线程选中执行
方法名描述
whenComplete(BiConsumer<? super T,? super Throwable> action)当CompletableFuture完成计算结果时对结果进行处理,或者当CompletableFuture产生异常的时候对异常进行处理。
whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)当CompletableFuture完成计算结果时对结果进行处理,或者当CompletableFuture产生异常的时候对异常进行处理。使用ForkJoinPool。
whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)当CompletableFuture完成计算结果时对结果进行处理,或者当CompletableFuture产生异常的时候对异常进行处理。使用指定的线程池。

handle()相当于whenComplete()+转换。

handle()也可以理解为和thenApply()的含义更为相似,但是比thenApply()增加异常处理的功能。

方法名描述
handle(BiFunction<? super T, Throwable, ? extends U> fn)当CompletableFuture完成计算结果或者抛出异常的时候,执行提供的fn
handleAsync(BiFunction<? super T, Throwable, ? extends U> fn)当CompletableFuture完成计算结果或者抛出异常的时候,执行提供的fn,使用ForkJoinPool。
handleAsync(BiFunction<? super T, Throwable, ? extends U> fn, Executor executor)当CompletableFuture完成计算结果或者抛出异常的时候,执行提供的fn,使用指定的线程池。
方法名描述
exceptionally(Function fn)只有当CompletableFuture抛出异常的时候,才会触发这个exceptionally的计算,调用function计算值。

纯消费

方法名描述
thenAccept(Consumer<? super T> action)当CompletableFuture完成计算结果,只对结果执行Action,而不返回新的计算值
thenAcceptAsync(Consumer<? super T> action)当CompletableFuture完成计算结果,只对结果执行Action,而不返回新的计算值,使用ForkJoinPool。
thenAcceptAsync(Consumer<? super T> action, Executor executor)当CompletableFuture完成计算结果,只对结果执行Action,而不返回新的计算值

Either

Either 表示的是两个CompletableFuture,当其中任意一个CompletableFuture计算完成的时候就会执行。
方法名描述
acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)当任意一个CompletableFuture完成的时候,action这个消费者就会被执行。
acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)当任意一个CompletableFuture完成的时候,action这个消费者就会被执行。使用ForkJoinPool
acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor)当任意一个CompletableFuture完成的时候,action这个消费者就会被执行。使用指定的线程池
applyToEither()acceptEither()的哥哥. 当两个future其中一个完成后,后者用于只是简单地调用一些代码,applyToEither()会返回一个新的future. 这个future是在前面两个future其中一个完成后进行执行完成。
方法名描述
applyToEither(CompletionStage<? extends T> other, Function<? super T,U> fn)当任意一个CompletableFuture完成的时候,fn会被执行,它的返回值会当作新的CompletableFuture<U>的计算结果。
applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn)当任意一个CompletableFuture完成的时候,fn会被执行,它的返回值会当作新的CompletableFuture<U>的计算结果。使用ForkJoinPool
applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn, Executor executor)当任意一个CompletableFuture完成的时候,fn会被执行,它的返回值会当作新的CompletableFuture<U>的计算结果。使用指定的线程池

其他方法

方法名描述
allOf(CompletableFuture<?>... cfs)在所有Future对象完成后结束,并返回一个future。
anyOf(CompletableFuture<?>... cfs)在任何一个Future对象结束后结束,并返回一个future。

以上是关于Java8 CompletableFuture 总结的主要内容,如果未能解决你的问题,请参考以下文章

Java8 CompletableFuture 总结

Java8新的异步编程方式 CompletableFuture

Java8 增强的Future:CompletableFuture

Java8已经发布7年了,不会还有人没用过CompletableFuture吧

《Java8实战》读书笔记10:组合式异步编程 CompletableFuture

《Java8实战》读书笔记10:组合式异步编程 CompletableFuture