Java8 中增强 Future:CompletableFuture

增强的 Future:CompletableFuture

CompletableFuture(它实现了 Future 接口) 和 Future 一样,可以作为函数调用的契约。当你向它请求获得结果,如果数据还没有准备好,请求线程就会等待,直到数据准备好后返回。

异步执行

@Test
public void testFuture() throws ExecutionException, InterruptedException {
    long t1 = System.currentTimeMillis();
    Future> listFuture = getListAsync();
    System.out.println("do something...");
    Thread.sleep(2_000L);
    System.out.println("getList...");
    System.out.println(listFuture.get());
    System.out.println("spendTime = " + (System.currentTimeMillis() - t1));
}
private Future> getListAsync() {
    CompletableFuture> resultFuture = new CompletableFuture<>();
    new Thread( () -> {
        try {
            Thread.sleep(3_000L);
            resultFuture.complete(Lists.newArrayList(1, 2, 3));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }).start();
    return resultFuture;
}

执行结果:

do something...

getList...

[1, 2, 3]
spendTime = 3137

以上代码中,do something 指主线程在调用过 Future 的异步接口取得凭证后,即可继续向下执行,直至 getList 需要通过凭证取得异步计算结果时,再通过 get 的方式取得。

如果采用同步调用的方式,那么以上程序则需要 3 + 2 共 5s 的时间。

使用 supplyAsync 创建 CompletableFuture

CompletableFuture 提供了更轻巧的工厂方法

Java8 中增强 Future:CompletableFuture
@Test
public void testFuture() throws ExecutionException, InterruptedException {
    long t1 = System.currentTimeMillis();
//    Future> listFuture = getListAsync();
    CompletableFuture> listFuture = CompletableFuture.supplyAsync(OrderThriftServiceTest::getList);
    System.out.println("do something...");
    Thread.sleep(2_000L);
    System.out.println("getList...");
    System.out.println(listFuture.get());
    System.out.println("spendTime = " + (System.currentTimeMillis() - t1));
}
private static List getList() {
    try {
        Thread.sleep(3_000L);
        return Lists.newArrayList(1,2,3,4,5);
    } catch (InterruptedException e) {
        e.printStackTrace();
        return Lists.newArrayList();
    }
}

View Code

对两个 CompletableFuture 的整合

compose 与 combine

compose,在一个 CompletableFuture 执行完毕后,将执行结果通过 Function 传递给下一个 Future 进行处理。

combine,将两个 CompletableFuture 整合起来,无论它们是否存在依赖。它接受 BiFunction 第二参数,这个参数定义了当两个 CompletableFuture 对象执行完计算后,结果如何合并。

两者都提供了后缀为 Async 的版本,该方法会将后续的任务提交到一个线程池中。其中 composeAsync 其实意义不大,因为 compose 操作的时间取决于第一个 CompletableFuture 的执行时间,composeAsync 相较 compose 消耗更多的线程切换开销。

一点实际应用

在服务化的项目中,一个服务调用另一个服务所提供的批量接口,如果一次调用的量过大那么将耗费很长时间,通过 CompletableFuture 可以暂缓一些时间,用作做执行别的任务

更加优化的做法是将大批量请求分成若干个合理大小的小批量请求(每个服务一般都是多机部署的,这样多个请求通过负载均衡打到多台机器,达到了并行运算的效果),还是通过 CompletableFuture 的方式,最终将结果进行组合,组合的过程就可以用 combine 来进行,而不是先 get 再 addAll 这种 low 的做法。

CompletableFuture> f1 = CompletableFuture.supplyAsync(OrderThriftServiceTest::getList);
CompletableFuture> f2 = CompletableFuture.supplyAsync(OrderThriftServiceTest::getList);
CompletableFuture> f3 = f1.thenCombineAsync(f2, (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(toList()));// doSomething...f3.get();

参考资料

[1] Java8 实战. 第 11 章

[2] Java 高并发程序设计. 6.5

Original: https://www.cnblogs.com/zhengbin/p/9000073.html
Author: 郑斌blog
Title: Java8 中增强 Future:CompletableFuture

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/537773/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Redis

    404. 抱歉,您访问的资源不存在。 可能是网址有误,或者对应的内容被删除,或者处于私有状态。 代码改变世界,联系邮箱 contact@cnblogs.com 园子的商业化努力-困…

    Java 2023年6月9日
    079
  • Java HashMap

    一些数据结构的操作性能 数组:查找快,新增、删除慢 采用一段连续的存储单元来存储数据 指定下标的查找,时间复杂度为 O(1) 通过给定值进行查找,需要遍历数组,逐一比对给定关键字和…

    Java 2023年5月29日
    0114
  • leetcode 83. Remove Duplicates from Sorted List 删除排序链表中的重复元素(简单)

    一、题目大意 给定一个已排序的链表的头 head , 删除所有重复的元素,使每个元素只出现一次 。返回 已排序的链表 。 示例 1: 输入:head = [1,1,2]输出:[1,…

    Java 2023年6月14日
    0125
  • Java集合—ArrayList

    集合和数组的区别 共同点:都是存储数据的容器 不同点:数组的容量是固定的,集合的容量是可变的 ArrayList的构造方法和添加方法 public ArrayList() 创建一个…

    Java 2023年6月15日
    081
  • 【Java面试】什么是令牌桶限流算法

    当面试官问你,”什么是令牌桶限流算法”!你知道要怎么回答,才能获得面试官的青睐吗?大家好,我是Mic,一个工作了14年的Java程序员。关于这个问题,面试官…

    Java 2023年6月16日
    092
  • 25. Apache Shiro Java反序列化漏洞

    前言: 最近在审核漏洞的时候,发现尽管Apache shiro这个反序列化漏洞爆出来好久了,但是由于漏洞特征不明显,并且shiro这个组件之前很少听说,导致大厂很多服务还存在shi…

    Java 2023年5月29日
    098
  • NGINX根据不同请求头参数,请求不同服务器

    在nginx的location配置中,在获取header配置时,须要在header名称前面加上固定前缀”http_”,并将header名称中的”…

    Java 2023年5月30日
    059
  • Java 反汇编指南javap

    前言 在正式解读《Effective Java》之前,我们需要先了解 Java 反汇编,因为反汇编是我们学习和研究问题的重要手段之一。 结合反汇编才能更好地理解《Effective…

    Java 2023年5月29日
    0101
  • SQLAlchemy完全入门

    最近想要学习 SQLAlchemy, 发现网上的中文文档大多是机翻的, 读起来特别变扭, 因此对照着最新的英文文档梳理了一遍, 写下来记录一下目前SQLAlchemy的版本为 1….

    Java 2023年6月7日
    089
  • nginx 安装

    一. 安装 使用 brew 安装: brew install nginx 1 ==> Installing dependencies for nginx: pcre 2 ==…

    Java 2023年5月30日
    091
  • Win7系统安装JDK后javac不是内部或外部命令解决办法

    2022年3月2日 20:48:28 好久没有写博客了,回老家的两年里,基本搁置下了编程的学习,只是偶尔用VBA做些工作上的小程序,之前的C#也早已忘得差不多了。但是最近总是想做一…

    Java 2023年5月29日
    077
  • spring boot、spring cloud、spring cloud alibaba、nacos之间的版本对应

    1、刚开始,我的spring cloud alibaba的版本为2.1.0,nacos版本为1.4.1 然后报错如下: 说明没有读取到nacos中的配置,nacos中的配置如下: …

    Java 2023年5月30日
    066
  • 9、线程礼让yield

    线程礼让: 1、让正在执行的线程为暂停,但不阻塞; 2、让状态转为就绪 3、让cpu重写调度,礼让不一定成功; Thread.currentThread()获取当前线程的引用 Or…

    Java 2023年6月8日
    074
  • Java 设计模式 – Observer 观察者模式

    说明都在注释: package ObserverModel; package ObserverModel; <span class="hljs-keyword&qu…

    Java 2023年6月9日
    059
  • 朱晔和你聊Spring系列S1E1:聊聊Spring家族的几大件

    朱晔和你聊Spring系列S1E1:聊聊Spring家族的几大件 【下载本文PDF进行阅读】 Spring家族很庞大,从最早先出现的服务于企业级程序开发的Core、安全方面的Sec…

    Java 2023年5月30日
    0111
  • 一个人成为废物得九大特质

    成为废物的九大特质 决定事情犹豫不决,优柔寡断 很强得拖延症 做什么事都三分钟热度 害怕被拒绝 自我设限(百度一下,你就知道) 经常逃避现实,不敢面对现实 总是能找到各种借口 总是…

    Java 2023年6月7日
    091
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球