CompletableFuture(二)
来源:互联网 发布:知不足者好学的下一句 编辑:程序博客网 时间:2024/05/29 18:45
转载自:http://www.jb51.net/article/51163.htm
创造和获取CompletableFuture
static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier);static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor);static CompletableFuture<Void> runAsync(Runnable runnable);static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor);
转换和作用于CompletableFuture(thenApply)
CompletableFuture优于Future,因为CompletableFuture是一个原子也是一个因子。Scala和JavaScript都允许future完成时允许注册异步回调,直到它准备好才要等待和阻止它。可以简单地说:运行这个函数时就出现了结果。此外,可以叠加这些功能,把多个future通过thenApply()组合在一起:ExecutorService executor = Executors.newFixedThreadPool(5);CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { return "zero";}, executor);CompletableFuture<Integer> f2 = f1.thenApply(new Function<String, Integer>() { @Override public Integer apply(String t) { System.out.println(2); return Integer.valueOf(t.length()); }});CompletableFuture<Double> f3 = f2.thenApply(r -> r * 2.0);System.out.println(f3.get());运行结果:
zero8.0注意,不是以Async结尾的方法将在future完成的相同线程中调用该方法中的参数,而以Async结尾的方法将在不同的线程池中异步地调用方法中的参数。
运行完成的代码(thenAccept/thenRun)
CompletableFuture<Void> thenAccept(Consumer<? super T> block);CompletableFuture<Void> thenRun(Runnable action);在future的管道里有两种典型的“最终”阶段方法,可以理解为回调函数。…Async变量也可用两种方法,隐式和显式执行器,thenAccept()/thenRun()方法并没有发生阻塞(即使没有明确的executor)。它们像一个事件侦听器/处理程序。
单个CompletableFuture的错误处理
CompletableFuture<String> safe = future.exceptionally(ex -> "We have a problem: " + ex.getMessage());exceptionally()接受一个函数时,将调用原始future来抛出一个异常。这里会有机会将此异常转换为和Future类型的兼容的一些值来进行恢复。safe进一步的转换将不再产生一个异常而是从提供功能的函数返回一个String值。一个更加灵活的方法是handle()接受一个函数,它接收正确的结果或异常:
CompletableFuture<Double> future = f2.thenApply(r -> r * 2.0);future.handle(new BiFunction<Double, Throwable, Double>(){ @Override public Double apply(Double t, Throwable u) {if (t != null) { System.out.println("handler"); return t;}else { System.out.println(u); return -1.0;} }}handle()总是被调用,结果和异常都非空,这是个一站式全方位的策略。
结合(链接)两个futures(thenCompose())
有时想运行一些future的值(当它准备好了),但这个函数也返回了future。CompletableFuture足够灵活地明白函数结果现在应该作为顶级的future,对比CompletableFuture<U> thenCompose(Function<? super T, Function<? super T, ? extends CompletionStage<U>> fn);//(CompletableFuture extends CompletionStage) public static void f5() throws InterruptedException, ExecutionException { ExecutorService executor = Executors.newFixedThreadPool(5); CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { return "zero"; }, executor); CompletableFuture<CompletableFuture<String>> f4 = f1.thenApply(CompletableFutureTest::calculate); System.out.println(f4.get().get()); CompletableFuture<String> f5 = f1.thenCompose(CompletableFutureTest::calculate); System.out.println(f5.get()); System.out.println(f1.get()); } public static CompletableFuture<String> calculate(String input) { ExecutorService executor = Executors.newFixedThreadPool(5); CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> { System.out.println(input); return input + "---" + input.length(); }, executor); return future; }仔细观察thenApply()(map)和thenCompose()(flatMap)的类型和差异.thenCompose()是一个重要的方法允许构建健壮的和异步的管道,没有阻塞和等待的中间步骤。
两个futures的转换值(thenCombine())
当thenCompose()用于链接一个future时依赖另一个thenCombine,当他们都完成之后就结合两个独立的futures:public <U,V> CompletableFuture<V> thenCombine( CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn)假设有两个CompletableFuture,一个加载Customer另一个加载最近的Shop。他们彼此完全独立,但是当他们完成时,想要使用它们的值来计算Route。这是一个可剥夺的例子:
CompletableFuture<Customer> customerFuture = loadCustomerDetails(123);CompletableFuture<Shop> shopFuture = closestShop();CompletableFuture<Route> routeFuture =customerFuture.thenCombine(shopFuture, (cust, shop) -> findRoute(cust, shop));private Route findRoute(Customer customer, Shop shop) //...注意,在Java 8中可以用(cust, shop) -> findRoute(cust, shop)简单地代替this::findRoute方法的引用:
customerFuture.thenCombine(shopFuture, this::findRoute);有customerFuture 和 shopFuture。那么routeFuture包装它们然后“等待”它们完成。当他们准备好了,它会运行提供的函数来结合所有的结果 (findRoute())。当两个基本的futures完成并且 findRoute()也完成时,这样routeFuture将会完成。
ExecutorService executor = Executors.newFixedThreadPool(5);CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { return "zero";}, executor);CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> { return "hello";}, executor);CompletableFuture<String> reslutFuture = f1.thenCombine(f2, new BiFunction<String, String, String>() { @Override public String apply(String t, String u) { return t.concat(u); } });System.out.println(reslutFuture.get());//zerohello
等待所有的 CompletableFutures 完成
如果不是产生新的CompletableFuture连接这两个结果,我们只是希望当完成时得到通知,我们可以使用 thenAcceptBoth()/runAfterBoth()系列的方法。它们的工作方式与thenAccept() 和 thenRun()类似,但是是等待两个futures而不是一个:public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action)public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action)示例:
ExecutorService executor = Executors.newFixedThreadPool(5);CompletableFuture<String> f1 = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(1); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return "zero";}, executor);CompletableFuture<String> f2 = CompletableFuture.supplyAsync(() -> { try { TimeUnit.SECONDS.sleep(3); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return "hello";}, executor);CompletableFuture<Void> reslutFuture = f1.thenAcceptBoth(f2, new BiConsumer<String, String>() { @Override public void accept(String t, String u) { System.out.println(t + " over"); System.out.println(u + " over"); }});System.out.println(reslutFuture.get());运行结果:
zero overhello overnull好了,你当然可以这么做。但是最关键的一点是CompletableFuture是允许异步的,它是事件驱动的编程模型而不是阻塞并急切地等待着结果。所以在功能上,上面两部分代码是等价的,但后者没有必要占用一个线程来执行。
等待第一个 CompletableFuture 来完成任务
另一个有趣的事是CompletableFutureAPI可以等待第一个(与所有相反)完成的future。当有两个相同类型任务的结果时就显得非常方便,只要关心响应时间就行了,没有哪个任务是优先的。public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action)作为一个例子,当有两个系统可以集成。一个具有较小的平均响应时间但是拥有高的标准差,另一个一般情况下较慢,但是更加容易预测。为了两全其美(性能和可预测性)可以在同一时间调用两个系统并等着谁先完成。通常这会是第一个系统,但是在进度变得缓慢时,第二个系统就可以在可接受的时间内完成:
完整地转换第一个系统
applyToEither()算是 acceptEither()的前辈了。当两个futures快要完成时,后者只是简单地调用一些代码片段,applyToEither()将会返回一个新的future。当这两个最初的futures完成时,新的future也会完成。public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn)
多种结合的CompletableFuture
知道如何等待两个future来完成(使用thenCombine())并第一个完成(applyToEither())。但它可以扩展到任意数量的futures吗?的确,使用static辅助方法:public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)allOf()当所有的潜在futures完成时,使用了一个futures数组并且返回一个future(等待所有的障碍)。另一方面 anyOf()将会等待最快的潜在futures。
0 0
- CompletableFuture(二)
- Java8的CompletableFuture之二
- CompletableFuture(一)
- CompletableFuture(三)
- CompletableFuture
- CompletableFuture
- CompletableFuture
- CompletableFuture
- 多线程之CompletableFuture(上)
- 多线程之CompletableFuture(中)
- 多线程之CompletableFuture(下)
- java CompletableFuture初探 (并发小实验)
- 疯狂Java学习(86)-----------使用CompletableFuture处理异步超时
- Java学习(86)-----------使用CompletableFuture处理异步超时
- java8新特性(九):CompletableFuture多线程并发异步编程
- java8-[CompletableFuture]
- CompletableFuture用法
- Java8-CompletableFuture
- 推荐系统学习之概率算法及其增量算法
- CrazyFlie源码学习2-Stabilizer任务
- android适配
- LLVM
- java_67---67,68没有看,pass
- CompletableFuture(二)
- 二维LIS Gym100820G Racing Gems
- P25 (*) Generate a random permutation of the elements of a list.
- [Leetcode] 98. Validate Binary Search Tree @python
- 模版方法模式
- 2015年第六届蓝桥杯C/C++程序设计本科B组省赛 牌型种数(结果填空)
- js的作用域学习笔记
- android Http通信局域网测试详解
- Ubuntu12.04安装中文输入法