前面两篇文章已经整理了CompletableFuture大部分的特性,本文会整理完CompletableFuture余下的特性,以及将它跟RxJava进行比较。

3.6 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这个消费者就会被执行。使用指定的线程池
        Random random = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<Void> future =  future1.acceptEither(future2,str->System.out.println("The future is "+str));try {future.get();} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}复制代码

执行结果:The future is from future1 或者 The future is from future2。
因为future1和future2,执行的顺序是随机的。

applyToEither 跟 acceptEither 类似。

方法名 描述
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>的计算结果。使用指定的线程池
        Random random = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(()->{try {Thread.sleep(random.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<String> future =  future1.applyToEither(future2,str->"The future is "+str);try {System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}复制代码

执行结果也跟上面的程序类似。

3.7 其他方法

allOf、anyOf是CompletableFuture的静态方法。

3.7.1 allOf

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

allOf()方法所返回的CompletableFuture,并不能组合前面多个CompletableFuture的计算结果。于是我们借助Java 8的Stream来组合多个future的结果。

        CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "tony");CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "cafei");CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> "aaron");CompletableFuture.allOf(future1, future2, future3).thenApply(v ->Stream.of(future1, future2, future3).map(CompletableFuture::join).collect(Collectors.joining(" "))).thenAccept(System.out::print);复制代码

执行结果:

tony cafei aaron复制代码

3.7.2 anyOf

方法名 描述
anyOf(CompletableFuture<?>... cfs) 在任何一个Future对象结束后结束,并返回一个future。
        Random rand = new Random();CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future1";});CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future2";});CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {try {Thread.sleep(rand.nextInt(1000));} catch (InterruptedException e) {e.printStackTrace();}return "from future3";});CompletableFuture<Object> future =  CompletableFuture.anyOf(future1,future2,future3);try {System.out.println(future.get());} catch (InterruptedException e) {e.printStackTrace();} catch (ExecutionException e) {e.printStackTrace();}复制代码

使用anyOf()时,只要某一个future完成,就结束了。所以执行结果可能是"from future1"、"from future2"、"from future3"中的任意一个。

anyOf 和 acceptEither、applyToEither的区别在于,后两者只能使用在两个future中,而anyOf可以使用在多个future中。

3.8 CompletableFuture异常处理

CompletableFuture在运行时如果遇到异常,可以使用get()并抛出异常进行处理,但这并不是一个最好的方法。CompletableFuture本身也提供了几种方式来处理异常。

3.8.1 exceptionally

方法名 描述
exceptionally(Function fn) 只有当CompletableFuture抛出异常的时候,才会触发这个exceptionally的计算,调用function计算值。
        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).exceptionally(t -> {System.out.println("Unexpected error:" + t);return null;});复制代码

执行结果:

Unexpected error:java.util.concurrent.CompletionException: java.lang.NullPointerException复制代码

对上面的代码稍微做了一下修改,修复了空指针的异常。

        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {
//                    s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).exceptionally(t -> {System.out.println("Unexpected error:" + t);return null;});复制代码

执行结果:

11复制代码

3.8.2 whenComplete

whenComplete 在上一篇文章其实已经介绍过了,在这里跟exceptionally的作用差不多,可以捕获任意阶段的异常。如果没有异常的话,就执行action。

        CompletableFuture.supplyAsync(() -> "hello world").thenApply(s -> {s = null;int length = s.length();return length;}).thenAccept(i -> System.out.println(i)).whenComplete((result, throwable) -> {if (throwable != null) {System.out.println("Unexpected error:"+throwable);} else {System.out.println(result);}});复制代码

执行结果:

Unexpected error:java.util.concurrent.CompletionException: java.lang.NullPointerException复制代码

跟whenComplete相似的方法是handle,handle的用法在上一篇文章中也已经介绍过。

四. CompletableFuture VS Java8 Stream VS RxJava1 & RxJava2

CompletableFuture 有很多特性跟RxJava很像,所以将CompletableFuture、Java 8 Stream和RxJava做一个相互的比较。

composable lazy resuable async cached push back pressure
CompletableFuture 支持 不支持 支持 支持 支持 支持 不支持
Stream 支持 支持 不支持 不支持 不支持 不支持 不支持
Observable(RxJava1) 支持 支持 支持 支持 支持 支持 支持
Observable(RxJava2) 支持 支持 支持 支持 支持 支持 不支持
Flowable(RxJava2) 支持 支持 支持 支持 支持 支持 支持

五. 总结

Java 8提供了一种函数风格的异步和事件驱动编程模型CompletableFuture,它不会造成堵塞。CompletableFuture背后依靠的是fork/join框架来启动新的线程实现异步与并发。当然,我们也能通过指定线程池来做这些事情。

CompletableFuture特别是对微服务架构而言,会有很大的作为。举一个具体的场景,电商的商品页面可能会涉及到商品详情服务、商品评论服务、相关商品推荐服务等等。获取商品的信息时(/productdetails?productid=xxx),需要调用多个服务来处理这一个请求并返回结果。这里可能会涉及到并发编程,我们完全可以使用Java 8的CompletableFuture或者RxJava来实现。

先前的文章:
Java8新的异步编程方式 CompletableFuture(一)
Java8新的异步编程方式 CompletableFuture(二)

Java8新的异步编程方式 CompletableFuture(三)相关推荐

  1. Java 8 的异步编程利器 CompletableFuture 真香!

    大家好,我是不才陈某~ 最近刚好使用CompeletableFuture优化了项目中的代码,所以跟大家一起学习CompletableFuture. 一个例子回顾 Future 因为Completabl ...

  2. Java 8 的异步编程利器 CompletableFuture 详解

    文章目录 一个例子回顾 Future 一个例子走进CompletableFuture CompletableFuture使用场景 创建异步任务 supplyAsync方法 runAsync方法 任务异 ...

  3. 硬核!Rust异步编程方式重大升级:新版Tokio如何提升10倍性能详解

    导读:协程或者绿色线程是近年来经常讨论的话题.Tokio作为Rust上协程调度器实现的典型代表,其设计和实现都有其特色.本文是Tokio团队在新版本调度器发布后,对其设计和实现的经验做的总结,十分值得 ...

  4. Java8新特性函数式编程

    一.函数式编程-Stream流 Stream API −新添加的Stream API(java.util.stream) 把真正的函数式编程风格引入到Java中.它可以被用来对集合或者数组进行链状流式 ...

  5. Java如何定义三个圆_java – 以编程方式查找三个圆的交叉点

    你可以从 C code获得帮助.把它移植到JAVA不应该是具有挑战性的.说明是 here.搜索/滚动到:两个圆的交点 使用此方法,找到任意两个圆的交点..让我们说(x,y).现在,只有当中心与点x,y ...

  6. 话说js中的异步编程。

    转载自品略图书馆 http://www.pinlue.com/article/2020/07/0412/3110968788347.html JS异步编程模型 在理解js异步编程时, 我们先再心中想一 ...

  7. 浅谈js中的异步编程

    转载自品略图书馆 http://www.pinlue.com/article/2020/07/0412/3110968788347.html JS异步编程模型 在理解js异步编程时, 我们先再心中想一 ...

  8. JS 异步编程都有哪些方案

    JS 异步编程都有哪些方案   先一起来回想一下,我们在日常开发中都用过哪些 JS异步编程的方式?总结起来无外乎有这几种:回调函数.事件监听.Promise.Generator.async/await ...

  9. java 并发 异步_Java并发 CompletableFuture异步编程的实现

    前面我们不止一次提到,用多线程优化性能,其实不过就是将串行操作变成并行操作.如果仔细观察,你还会发现在串行转换成并行的过程中,一定会涉及到异步化,例如下面的示例代码,现在是串行的,为了提升性能,我们得 ...

最新文章

  1. 550种Blender风格化笔刷素材
  2. CVPR 2020录用率十年最低,商汤官宣62篇入选
  3. win7+jdk环境变量配置
  4. 9月份准备备考RHCE 10份考试争取一次通过
  5. morphia(1)-基础
  6. MySQL带BETWEEN AND关键字的查询
  7. ftp搭建后为什么登录不了??_为什么防爆胎就是普及不了?知道真相后,你也许会心凉一大截...
  8. Qt入门之常用qt控件认知之QLabel
  9. caffe:无法读取文件cuda8.0.props
  10. 操作系统面试题目详解
  11. Python学习笔记(运算符)
  12. 飞鸽传书下载 分析企业OpenEIM
  13. 安卓原生读写u盘_aigo Type-C固态U盘速度如何?好用吗?
  14. redis 如何查看某个库的key_如何发现 Redis 热点 Key ,解决方案有哪些?
  15. 《致云雀》(英)雪莱
  16. hibernate枚举类型注解 @Enumerated
  17. 揭秘Facebook数据库备份策略
  18. java图形编程正三角形_java实现正三角形和到正三角形
  19. java实现excel导入导出,对象图片读取,上传七牛云
  20. 【OpenGL】笔记二十七、几何着色器

热门文章

  1. linux中的fork方法(python)
  2. 三年经验前端社招——丰巢科技
  3. 「前端工程化」该怎么理解?
  4. 《大规模分布式系统架构与设计实战》
  5. PostgreSQL Huge Page 使用建议 - 大内存主机、实例注意
  6. Part 3: Services
  7. 如何使用PowerShell提升开发效率(以Windows Embedded CE为例)
  8. 无线安全***--启程
  9. 英文版opensuse 12.2安装中文输入法ibus
  10. 老歌新唱--使用VB6开发的ActiveX实现.NET程序的混淆加密