当前位置: 首页 > news >正文

Java8 中增强 Future:CompletableFuture

增强的 Future:CompletableFuture

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

异步执行

@Test 
public void testFuture() throws ExecutionException, InterruptedException { 
    long t1 = System.currentTimeMillis(); 
    Future<List<Integer>> 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<List<Integer>> getListAsync() { 
    CompletableFuture<List<Integer>> 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 提供了更轻巧的工厂方法

@Test 
public void testFuture() throws ExecutionException, InterruptedException { 
    long t1 = System.currentTimeMillis(); 
//    Future<List<Integer>> listFuture = getListAsync(); 
    CompletableFuture<List<Integer>> 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<Integer> 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<List<Integer>> f1 = CompletableFuture.supplyAsync(OrderThriftServiceTest::getList);
CompletableFuture<List<Integer>> f2 = CompletableFuture.supplyAsync(OrderThriftServiceTest::getList);
CompletableFuture<List<Integer>> f3 = f1.thenCombineAsync(f2, (l1, l2) -> Stream.concat(l1.stream(), l2.stream()).collect(toList()));
// doSomething...
f3.get();

参考资料

[1] Java8 实战. 第 11 章

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

相关文章:

  • 精彩源于起点——2018年潍坊市首次青少年Python编程公开课
  • 远程连不上服务器 解决方案
  • Python十分钟制作属于你自己的个性logo
  • ​七周四次课(5月9日)iptables filter表案例、iptables nat表应用
  • 并发容器与框架——Fork/Join框架
  • Hadoop2.4.1的HA的配置与启动
  • Unity全新的版本发布计划(2018)
  • Ora 28040
  • 2016中国“互联网+”创业创新大赛(西北+山西)赛区决赛成功举办 优秀项目将会师海口...
  • python 文件调用其他路径
  • 每日linux命令之kill
  • 双杠仰卧起坐
  • cisco CCNA CCNP CCIE 学习资料整理
  • sql server 2008 身份验证失败 18456
  • 3D Lut 电影级调色算法 附完整C代码
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • ES6 ...操作符
  • iOS仿今日头条、壁纸应用、筛选分类、三方微博、颜色填充等源码
  • nginx 负载服务器优化
  • Odoo domain写法及运用
  • RxJS 实现摩斯密码(Morse) 【内附脑图】
  • Spring Cloud Alibaba迁移指南(一):一行代码从 Hystrix 迁移到 Sentinel
  • 程序员该如何有效的找工作?
  • 海量大数据大屏分析展示一步到位:DataWorks数据服务+MaxCompute Lightning对接DataV最佳实践...
  • 爬虫模拟登陆 SegmentFault
  • 前端js -- this指向总结。
  • 使用SAX解析XML
  • 为物联网而生:高性能时间序列数据库HiTSDB商业化首发!
  • 转载:[译] 内容加速黑科技趣谈
  • 【运维趟坑回忆录 开篇】初入初创, 一脸懵
  • ​软考-高级-系统架构设计师教程(清华第2版)【第15章 面向服务架构设计理论与实践(P527~554)-思维导图】​
  • (BFS)hdoj2377-Bus Pass
  • (C++)八皇后问题
  • (二)丶RabbitMQ的六大核心
  • (太强大了) - Linux 性能监控、测试、优化工具
  • (转)ORM
  • .NET Core 和 .NET Framework 中的 MEF2
  • .NET Framework杂记
  • .NET 中使用 Mutex 进行跨越进程边界的同步
  • .NET 自定义中间件 判断是否存在 AllowAnonymousAttribute 特性 来判断是否需要身份验证
  • .NET6使用MiniExcel根据数据源横向导出头部标题及数据
  • ??javascript里的变量问题
  • []sim300 GPRS数据收发程序
  • [AutoSar]BSW_Memory_Stack_004 创建一个简单NV block并调试
  • [C++]指针与结构体
  • [C++核心编程](四):类和对象——封装
  • [HDU]2161Primes
  • [ios-必看] IOS调试技巧:当程序崩溃的时候怎么办 iphone IOS
  • [Luogu 2816]宋荣子搭积木
  • [nlp] 多语言大模型不同语种/语系数据的数据配比调节
  • [NSSCTF 2nd] web刷题记录
  • [Pytorch]:PyTorch中张量乘法大全
  • [SCOI2010]传送带
  • [SQL]实现按照指定分割分分割字符串
  • [Web开发] IE8的User-Agent 字符串