APP下载
报价宝  ›  科技  › 

Java8特性之CompletableFuture

报价宝 来源:baojiabao.com 发布时间:2019-07-06 09:48:00 10月02日更新
报价宝综合消息Java8特性之CompletableFuture

原文:https://blog.51cto.com/turnsole/2120848作者:Turnsole1

一. CompletableFuture

1.Future界面

Future设计的初衷:对将来某个时刻会发生的结果进行建模。

它建模了一种异步计算,返回一个执行运算结果的引用,当运算结束后,这个引用被返回给呼叫方。在Future中出发那些潜在耗时的操作把呼叫执行绪解放出来,让它能继续执行其他有价值的工作,不再需要等待耗时的操作完成。

Future的优点:比更底层的Thread更易用。

要使用Future,通常只需要将耗时的操作封装在一个Callable物件中,再将它提交给ExecutorService。

ExecutorService executor = Executors.newCachedThreadPool();

Future future = executor.submit(new Callable() { //向ExecutorService提交一个Callable物件

@Override

public Double call() throws Exception {

return doSomeLongComputation(); //以异步方式在新的执行绪中执行耗时的操作

}

});

doSomethingElse(); //异步操作进行的同时,你可以做其他的事情

try {

//获取异步操作的结果,如果最终被阻塞,无法得到结果,那么在最多等待1秒钟之后退出

Double result = future.get(1, TimeUnit.SECONDS);

} catch (ExecutionException ee) {

//加上丢掷一个异常

} catch (InterruptedException ie) {

//当前执行绪在等待过程中被中断

} catch (TimeoutException te) {

//在Future物件完成之前超过已过期

}

2. 实现异步API、程式码避免阻塞

使用工厂方法supplyAsync建立CompletableFuture

public Future getPriceAsync2(String product) {

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

}

supplyAsync方法接受一个生产者(Supplier)作为引数,返回一个CompletableFuture物件,该物件完成异步执行后会读取呼叫生产者方法的返回值。

生产者方法会交由ForkJoinPool池中的某个执行执行绪(Executor)执行,但是你也可以使用supplyAsync方法的过载版本,传递第二个引数指定不同的执行执行绪执行生产者方法。

join方法等待异步操作结束

CompletableFuture类中的join方法和Future界面中的get有相同的含义,等待执行结束。并且也宣告在Future界面中,唯一的不同是join方法不会丢掷任何检测到的异常。因此使用它时不需要再使用try/catch语句块。

public List findPrices(String product) {

//使用CompletableFuture以异步方式计算每种商品的价格

List> priceFutures = shops.stream()

.map(shop -> CompletableFuture.supplyAsync(() -> shop.getName() + " price is " + shop.getPriceAsync(product)))

.collect(Collectors.toList());

//等待所有异步操作结束

return priceFutures.stream().

map(CompletableFuture::join)

.collect(Collectors.toList());

}

使用定制执行器

建立一个配有执行绪池的执行器。

执行绪数的选择:N(threads) = N(CPU) * U(CPU) * (1 + W/C)

-- N(CPU):处理器的核的数目,可以通过Runtime.getRuntime().availableProcessors()得到;

-- U(CPU):期望的CPU利用率(该值应该介于0和1之间);

-- W/C:等待时间与计算时间的比率。

//建立一个执行绪池,执行绪池中执行绪的数目为100和商店数目二者中较小的一个值(这里100为执行绪池的上限)

private final Executor executor = Executors.newFixedThreadPool(Math.min(shops.size(), 100), new ThreadFactory() {

@Override

public Thread newThread(Runnable r) {

Thread t = new Thread(r);

t.setDaemon(true); //使用守护执行绪--这种方式不会阻止程式的关停

return t;

}

});

集合进行平行计算有两种方式:并行流和CompletableFutures。

-- 计算密集型操作,并且没有I/O,推荐使用Stream界面。因为实现简单,同时效率也可能是最高的(如果所有的执行绪都是计算密集型的,那就没有必要建立比处理器核数更多的执行绪);

-- 如果并行的工作单元还涉及等待I/O的操作(包括网络连线等待),那么使用CompletableFuture灵活性更好。这种情况下处理流的流水线中如果发生I/O等待,流的延迟特性会让我们很难判断到底什么时候触发了等待。

3. 对多个异步任务进行流水线操作

thenApply:将一个由字串转换Quote的方法作为引数传递给他

thenCompose:该方法允许你对两个异步操作进行流水线,第一个操作完成时,将其结果作为引数传递给第二个操作。

对第一个CompletableFuture物件呼叫thenCompose,并向其传递一个函式。当第一个CompletableFuture执行完毕后,他的结果将作为该函式的引数,这个函式的返回值是以第一个CompletableFuture的返回做输入计算出的第二 个CompletableFuture物件。使用thenCompose减少很多执行绪切换开销。thenCombine:将两个CompletableFuture物件结果整合起来。该方法接收名为BiFunction的第二引数,这个引数定义了两个CompletableFuture物件完成计算后,如何合并。

thenAccept:方法接收CompletableFuture执行完毕后的返回值做引数。不必等待那些还未返回的结果。

文章标签: 报价宝 降噪耳机价格 耳机价格 红米手机价格 华为手机价格 小米手机价格 电视机价格 笔记本电脑价格 笔记本价格 汽车价格 手机价格 笔记本价格 笔记本电脑价格 电视机价格 华为手机价格