若你的意图是并发,而非并行,或者你的主要目标是在同一个CPU上执行几个松耦合的任务,充分利用CPU的核,让其足够忙碌,从而最大化程序的吞吐量,那么其实真正想做的避免因为等待远程服务的返回,或对数据库的查询而阻塞线程的执行,浪费计算资源。

  

  Future接口在Java 5中引入,设计初衷是对将来某个时刻会发生的结果进行建模。它建模了一种异步计算,返回一个执行计算结果的引用。使用Future只需要将耗时的操作封装在一个Callable对象中,再将它提交给ExecutorService。可以调用get方法获取操作的结果。若操作已经完成,该方法会立刻返回操作的结果,否则它会阻塞你的线程,直到操作完成,返回响应的结果。Future还提供了一个参数设置超时时间,通过它可以定义线程等待Future结果的最长时间。

  Future接口的局限:  

    将两个异步计算合并为一个——这两个异步计算之间相互独立,同时第二个又依赖于第一个的结果

    等待Future集合中的所有任务都完成

    仅等待Future集合中最快结束的任务完成

    通过编程方式完成一个Future任务的执行

    应对Future的完成事件

  

  同步API和异步API

    同步API是对传统方法调用的另一种称呼:你调用了某个方法,调用方在被调用方运行的过程中会等待,被调用方运行结束返回,调用方取得被调用方的返回值并继续运行。即使调用方和被调用方在不同的线程中运行,调用方还需要等待被调用方结束运行,这就是阻塞时调用这个名词的由来。异步API会直接返回,至少在被调用方计算完成之前,将它的剩余的计算任务交给另一个线程去做,该线程和调用方是异步的,这就是非阻塞式调用的由来。执行剩余计算任务的线程会将它的计算结果返回给调用方。返回方式要么是通过回调函数,要么是调用方再次执行一个“等待,直到计算完成”的方法调用。

  若调用的方法出现了错误,用于提示错误会被限制在当前异步的线程内,从而导致get方法返回结果的客户端永久的被阻塞。客户端可以使用重载版本的get方法,使用一个超时参数来避免发生这样的情况。当超时发生时,程序会得到通知发生了TimeoutException。也可以使用CompletableFuture的completeExceptionally方法将导致CompletableFuture内发生问题的异常抛出。

    public Future<Double> getPrice(final String product){
CompletableFuture<Double> futurePrice = new CompletableFuture<>();
new Thread(() ->{
try{
double price = calculatePrice(product);
futurePrice.complete(price);
}catch (Exception e){
futurePrice.completeExceptionally(e);
} }).start();
return futurePrice;
}

  CompletableFuture的supplyAsync方法接受一个生产者(Supplier)作为参数,返回一个CompletableFuture对象,该对象完成异步执行后会读取调用生产者方法的返回值。生产者方法会交由ForkJoinPool池中的某个执行线程运行,但也可以使用supplyAsync方法的重载版本,传递第二个参数指定不同的执行线程执行生产者方法。

  因此上段代码可以简写成:

    public Future<Double> getPrice(final String product){

   return CompletableFuture.supplyAsync(() -> calculatePrice(product)); 

     }

  并行流及CompletableFuture

    并行流和CompletableFuture内部采用的都是同样的线程池,默认都是使用固定数目的线程,具体线程取决于Runtime.getRuntime().availableProcessors()的返回值。而CompletableFuture具有一定的优势,因为它允许你对执行器进行配置,尤其是线程池的大小,让它以更适应需求的方式进配置,满足程序的要求,这时并行流API无法提供的。

  若线程池中的线程数量过多,最终它们会竞争稀缺的处理器和内存资源,浪费大量的时间在上下文切换。若线程的数目过少,线程池大小与处理器的利用率之比可用下面的公式进行估算:

  N(threads) = N(cpu) * U(cps) * (1 + W/C);

    N(cpu)是处理器的核的数目,U(cpu)是期望的CPU的利用率,W/C是等待时间与计算时间的比值

  对集合进行并行计算有两种方式:一种是将其转化成并行流,利用map开展工作,另一种是枚举集合中的每个元素,创建新的线程,在CompletableFuture内进行操作。若进行的是计算密集型的操作,并且没有IO,推荐使用Stream接口。若涉及IO,则使用CompletableFuture接口。

  CompletableFuture.thenCompose()方法允许对两个异步操作进行流水线,第一个操作完成时,将其结果作为参数传递给第二个操作。thenComposeAsync()方法会将后续的任务提交到另个线程中运行。

  CompletableFuture.thenCombine()方法,它接受名为BiFunction的第二个参数,这个参数定义了当两个CompletableFuture对象完成计算后,结果如何合并。thenCombineAsync()方法会导致BiFunction中定义的合并操作被提交到线程池中,由另一个任务以异步的方式执行。

  Future<Double> futurePriceInUSD = CompletableFuture.supplyAsync(() -> shop.getPrice(produce))

                            .thenCombine(Completable.supplyAsync(() -> exchangeService.getRate(Money.EUR, Money.USD)), (price, rate) -> price * rate);

  CompletableFuture.thenAccept()执行完毕后的返回值做参数。异步版本的方法对处理结果的消费者进行调度,从线程池中选择一个新的线程继续执行,不再由同一个线程完成CompletableFuture的所有任务。一旦CompletableFuture计算到结果,它就返回一个CompletableFuture<Void>。

  CompletableFuture.allOff工厂方法接收由一个CompletableFuture构成的数组,数组中的所有CompletableFuture对象执行完成之后,它返回一个CompletableFuture<Void>对象。若需要等待最初的Stream中所有的CompletableFuture对象执行完毕,可以对allOf方法返回的CompletableFuture执行join操作。

  CompletableFuture.anyOf方法接受一个CompletableFuture对象构成的数组。返回由第一个执行完毕的CompletableFuture对象的返回值构成的CompletableFuture<Object>。

  long start = System.nanoTime();

  CompletableFuture[] futures = findPriceStream("product").map(f -> f.thenAccept(s -> System.out.println(s + " done in " + ((System.nanoTime() - start)/ 1000000) +" msecs"))).toArray(size -> new CompletableFuture[size]);

  CompletableFuture.allOf(futures).join();

  System.out.println("All shops have now responsed in " + ((System.nanoTime() - start )/ 100000) + " msces");

CompletableFuture的更多相关文章

  1. Java CompletableFuture 详解

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

  2. 多线程并发执行任务,取结果归集。终极总结:Future、FutureTask、CompletionService、CompletableFuture

    目录 1.Futrue 2.FutureTask 3.CompletionService 4.CompletableFuture 5.总结 ================正文分割线========= ...

  3. CompletableFuture CompletableFuture.supplyAsync 异常处理

    CompletableFuture 异常处理completeExceptionally可以把异常抛到主线程 /** * User: laizhenwei * Date: 2018-01-30 Time ...

  4. 使用CompletableFuture实现异步编程

    在开发中会碰到一种场景,如下 Object result1 = service1.func1();//执行80ms Object result2 =service2.func2();//执行50ms ...

  5. CompletableFuture基本用法

    异步计算 所谓异步调用其实就是实现一个可无需等待被调用函数的返回值而让操作继续运行的方法.在 Java 语言中,简单的讲就是另启一个线程来完成调用中的部分计算,使调用继续运行或返回,而不需要等待计算结 ...

  6. 使用CompletableFuture优化你的代码执行效率

    这篇文章详细讲解java8中CompletableFuture的特性,方法以及实例. 在java8以前,我们使用java的多线程编程,一般是通过Runnable中的run方法来完成,这种方式,有个很明 ...

  7. 多线程编程CompletableFuture与parallelStream

    一.简介 平常在页面中我们会使用异步调用$.ajax()函数,如果是多个的话他会并行执行相互不影响,实际上Completable我理解也是和它类似,是java 8里面新出的异步实现类,Completa ...

  8. 从CompletableFuture到异步编程设计

    从CompletableFuture到异步编程设计,笔者就分为2部分来分享CompletableFuture异步编程设计,前半部分总结下CompletableFuture使用实践,后半部分分享下Com ...

  9. Java CompletableFuture:allOf等待所有异步线程任务结束

    private void method() throws ExecutionException, InterruptedException { CompletableFuture<String& ...

  10. 【JUC源码解析】CompletableFuture

    简介 先说Future, 它用来描述一个异步计算的结果.isDone方法可以用来检查计算是否完成,get方法可以用来获取结果,直到完成前一直阻塞当前线程,cancel方法可以取消任务.而对于结果的获取 ...

随机推荐

  1. 剑指offer-栈的压入与弹出

    题目描述 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序 ...

  2. Beta阶段——第2篇 Scrum 冲刺博客

    Beta阶段--第2篇 Scrum 冲刺博客 标签:软件工程 一.站立式会议照片 二.每个人的工作 (有work item 的ID) 昨日已完成的工作 人员 工作 林羽晴 完成https安全连接的问题 ...

  3. Node+Express的跨域访问控制问题:Access-Control-Allow-Origin

    问题一:项目A通过Ajax访问项目B的接口,获取json数据,项目B采用Node+Express技术栈.项目A可能遇到跨域访问控制问题. 问题二:vue-resource 能够跨域,一般使用jsonp ...

  4. Space Ant

    Space Ant The most exciting space discovery occurred at the end of the 20th century. In 1999, scient ...

  5. Binary Analysis Tool安装使用教程

    Binary Analysis Tool(BAT)是一个用于检测二进制文件使用到的开源组件,协助及早发现程序发布后可能会面临的开源协议解执的开源免费检测工具. 一.安装BAT和bat-extratoo ...

  6. linux下查看物理CPU个数、核数、逻辑CPU个数

    cat /proc/cpuinfo中的信息 processor 逻辑处理器的id.physical id 物理封装的处理器的id.core id 每个核心的id.cpu cores 位于相同物理封装的 ...

  7. axios 参数为payload的解决方法

    1. 添加头部headers headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, axios.post(url, {a ...

  8. export及export default

    const a=2; const b=3; const c=function(){console.log(a+b} export a; export b; export default c; 如上文件 ...

  9. Uva LA 3177 - Beijing Guards 贪心,特例分析,判断器+二分,记录区间内状态数目来染色 难度: 3

    题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...

  10. Uva LV 2995 Image Is Everything 模拟,坐标映射,视图映射 难度: 1

    题目 https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_pr ...