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

Java里面CompletableFuture详解

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

Future是Java5添加的类,用来描述一个异步计算的结果。可以用isDone方法来检查计算是否完成,或者使用get阻塞住调用线程,直至计算完成返回结果,也可以用cancel方法来停止任务的执行。

 

[java] view plain copy

  1. public class BasicFuture {  
  2.     public static void main(String[] args) throws ExecutionException, InterruptedException {  
  3.         ExecutorService es = Executors.newFixedThreadPool(10);  
  4.         Future<Integer> f = es.submit(() -> {  
  5.             // 长时间的异步计算  
  6.             // ...  
  7.             // 然后返回结果  
  8.             return 100;  
  9.         });  
  10.         f.get();  
  11.     }  
  12. }  


Future以及相关使用方法提供了异步执行任务的能力,但对于结果的获取却是不方便,只能通过阻塞或轮询的方式得到任务结果。阻塞的方式与我们理解的异步编程其实是相违背的,而轮询又会耗无谓的CPU资源。而且还不能及时得到计算结果,为什么不能用观察者设计模式当计算结果完成及时通知监听者呢?

很多语言像Node.js,采用回调的方式实现异步编程。Java的一些框架像Netty,自己扩展Java的Future接口,提供了addListener等多个扩展方法:

 

[java] view plain copy

  1. ChannelFuture future = bootstrap.connect(new InetSocketAddress(host, port));  
  2.       future.addListener(new ChannelFutureListener()  
  3.       {  
  4.               @Override  
  5.               public void operationComplete(ChannelFuture future) throws Exception  
  6.               {  
  7.                   if (future.isSuccess()) {  
  8.                       // SUCCESS  
  9.                   }  
  10.                   else {  
  11.                       // FAILURE  
  12.                   }  
  13.               }  
  14.       });  

guava里面也提供了通用的扩展Future: ListenableFuture\SettableFuture以及辅助类Futures等,方便异步编程。

作为正统Java类库,是不是应该加点什么特性,可以加强一下自身库的功能?

Java8里面新增加了一个包含50个方法左右的类:CompletableFuture. 提供了非常强大的Future的扩展功能,可以帮助简化异步编程的复杂性,提供了函数式编程能力,可以通过回调的方式计算处理结果,并且提供了转换和组织CompletableFuture的方法。

主动完成计算

CompletableFuture 类实现了CompletionStage和Future接口,所以还是可以像以前一样通过阻塞或轮询的方式获得结果。尽管这种方式不推荐使用。

 

[java] view plain copy

  1. public T    get()  
  2. public T    get(long timeout, TimeUnit unit)  
  3. public T    getNow(T valueIfAbsent)  
  4. public T    join()  

其中的getNow有点特殊,如果结果已经计算完则返回结果或抛异常,否则返回给定的valueIfAbsent的值。

join返回计算的结果或抛出一个uncheckd异常。
 

尽管Future可以代表在另外的线程中执行一段异步代码,但你还是可以在本身线程中执行:

创建CompletableFuture对象

CompletableFuture.compleatedFuture是一个静态辅助方法,用来返回一个已经计算好的CompletableFuture.

以下四个静态方法用来为一段异步执行的代码创建CompletableFuture对象:

 

[java] view plain copy

  1. public static CompletableFuture<Void>     runAsync(Runnable runnable)  
  2. public static CompletableFuture<Void>     runAsync(Runnable runnable, Executor executor)  
  3. public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier)  
  4. public static <U> CompletableFuture<U>  supplyAsync(Supplier<U> supplier, Executor executor)  


以Async结尾并且没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。

runAsync方法:它以Runnabel函数式接口类型为参数,所以CompletableFuture的计算结果为空。

supplyAsync方法以Supplier<U>函数式接口类型为参数,CompletableFuture的计算结果类型为U。

方法的参数类型都是函数式接口,所以可以使用lambda表达式实现异步任务。如:

 

[java] view plain copy

  1. CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {  
  2.     //长时间的计算任务  
  3.     return "·00";  
  4. });  

计算结果完成时的处理

当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:

 

[java] view plain copy

  1. public CompletableFuture<T>   whenComplete(BiConsumer<? super T,? super Throwable> action)  
  2. public CompletableFuture<T>   whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)  
  3. public CompletableFuture<T>   whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)  
  4. public CompletableFuture<T>     exceptionally(Function<Throwable,? extends T> fn)  

可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。

方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)

 

[java] view plain copy

  1. public class BasicFuture {  
  2.   
  3.     private static Random rand = new Random();  
  4.     private static long t = System.currentTimeMillis();  
  5.   
  6.     static int getMoreData()  {  
  7.         System.out.println("begin to start compute");  
  8.         try {  
  9.             TimeUnit.SECONDS.sleep(3);  
  10.         } catch (InterruptedException e) {  
  11.             e.printStackTrace();  
  12.         }  
  13.         System.out.println("end to compute,passed " + (System.currentTimeMillis()-t));  
  14.         return rand.nextInt(1000);  
  15.     }  
  16.   
  17.   
  18.     public static void main(String[] args) throws ExecutionException, InterruptedException {  
  19.         CompletableFuture<Integer> future = CompletableFuture.supplyAsync(BasicFuture::getMoreData);  
  20.         Future<Integer> f = future.whenComplete((v,e) -> {  
  21.             System.out.println(v);  
  22.             System.out.println(e);  
  23.         });  
  24.         System.out.println(f.get());  
  25. }}  


下面一组方法虽然也返回CompletableFuture对象,但是对象的值和原来的CompletableFuture计算的值不同,当原先的CompletableFuture的值计算完成或抛异常的时候,会触发CompletableFuture对象的计算。

转换

CompletableFuture可以作为monad(单子)和functor. 由于回调风格的实现,我们不必因为等待一个计算完成而阻塞着调用线程,而是告诉CompletableFuture当计算完成的时候请执行某个Function. 还可以串联起来。

 

[java] view plain copy

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





 

参考:

http://colobu.com/2016/02/29/Java-CompletableFuture/

转载于:https://my.oschina.net/xiaominmin/blog/1620378

相关文章:

  • 10个最受欢迎的Java类
  • 国内 CDN 产品发展历史和现状整理
  • [译] 用 Java 创造你的第一个区块链-第一部分
  • vi
  • 文件上传下载
  • Flex与后台交互 鼠标忙时状态
  • 18.Azure备份(MARS)代理(下)
  • 5个能够有效帮助你快速创建超棒CSS3动画效果的类库
  • 用js实现页面跳转的几种方式
  • Bzoj1758: [Wc2010]重建计划
  • 图像编码介绍mark
  • redis集群部署及踩过的坑
  • 解决编译apache出现的问题:configure: error: APR not found . Please read the documentation
  • 找出OData service出错根源的小技巧
  • Quartz作业调度
  • 《微软的软件测试之道》成书始末、出版宣告、补充致谢名单及相关信息
  • 【面试系列】之二:关于js原型
  • Angular 2 DI - IoC DI - 1
  • CAP 一致性协议及应用解析
  • CSS居中完全指南——构建CSS居中决策树
  • ES6--对象的扩展
  • exports和module.exports
  • Java 网络编程(2):UDP 的使用
  • js ES6 求数组的交集,并集,还有差集
  • Octave 入门
  • PAT A1120
  • spring boot 整合mybatis 无法输出sql的问题
  • 编写高质量JavaScript代码之并发
  • 多线程 start 和 run 方法到底有什么区别?
  • 翻译:Hystrix - How To Use
  • 技术胖1-4季视频复习— (看视频笔记)
  • 如何学习JavaEE,项目又该如何做?
  • 深度学习中的信息论知识详解
  • 实战|智能家居行业移动应用性能分析
  • 使用 Docker 部署 Spring Boot项目
  • 它承受着该等级不该有的简单, leetcode 564 寻找最近的回文数
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 小程序测试方案初探
  • 仓管云——企业云erp功能有哪些?
  • ​油烟净化器电源安全,保障健康餐饮生活
  • #HarmonyOS:基础语法
  • #NOIP 2014# day.1 T2 联合权值
  • $jQuery 重写Alert样式方法
  • (done) NLP “bag-of-words“ 方法 (带有二元分类和多元分类两个例子)词袋模型、BoW
  • (done) 两个矩阵 “相似” 是什么意思?
  • (WSI分类)WSI分类文献小综述 2024
  • (第二周)效能测试
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (一)Neo4j下载安装以及初次使用
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • ***通过什么方式***网吧
  • .NET Core跨平台微服务学习资源
  • .NET 中什么样的类是可使用 await 异步等待的?
  • .NET成年了,然后呢?
  • .net对接阿里云CSB服务