Lagom学习 四 CompletionStage
Future: Java 8 之前的 Java 版本功能较弱,仅支持两种用法:要么检查 future 是否已经完成,要么等待 future 完成;
Java 8 增加了 CompletableFuture<T>
类,它实现了新的 CompletionStage<T>
接口,并对 Future<T>
进行了扩展。(都包含在 java.util.concurrent
包中。)CompletionStage
代表异步计算中的一个阶段或步骤。该接口定义了多种不同的方式,将CompletionStage
实例与其他实例或代码链接在一起,比如完成时调用的方法(一共 59 种方法,比Future
接口中的 5 种方法要多得多。)
CompletionStage
的接口一般都返回新的CompletionStage,表示执行完一些逻辑后,生成新的CompletionStage,构成链式的阶段型的操作。
Java 1.5 有了 Future, 可谓是跨了一大步,继而 Java 1.8 新加入一个 Future 的实现 CompletableFuture, 从此线程与线程之间可以愉快的对话了。最初两个线程间的协调我采用过 Object 的 wait()
和 notify()
, Thread 的 join()
方法,那可算是很低级的 API 了,是否很多 Java 程序都不知道它们的存在,或根本没用过它们。
如果是简单的等待所有线程完成可使用 Java 1.5 的 CountDownLatch, 这里有一篇介绍 CountDownLatch 协调线程, 就是实现的 waitAll(threads) 功能。而 Java 8 的 CompletableFuture
的功能就多去,可简单使用它实现异步方法。虽说 CompletableFuture
实现了 Future
接口,但它多数方法源自于 CompletionStage
, 所以还里氏代换,用 Future
来引用 CompletableFuture
实例就很牵强了; 这也是为什么 PlayFramework 自 2.5 开始直接暴露的类型是 CompletionStage
而非其他两个。
顾名思义,CompletableFuture 代表着一个 Future 完成后该干点什么,具体大致有:
- Future 完成后执行动作,或求取下一个 Future 的值。then...
- 多个 Future 的协调; 同时完成该怎么,其中一个完成该如何。allOf, anyOf
CompletableFuture
有太多太多的方法,并伴有 async
与 非 async
两个版本。试想一下,如过不用 Future
或 CompletableFuture
, 想要实现等待某个线程完成之后才做后续的事,可以用join或wait等。但是CompletableFuture更好。
同步和异步:
package completeFutture; import java.util.concurrent.CompletableFuture; public class Test { public static void main(String[] args) { CompletableFuture<Double> futurePrice = getPriceAsync(); //do anything you want, 当前线程不被阻塞 System.out.println(111); //线程任务完成的话,执行回调函数,不阻塞后续操作 futurePrice.whenComplete((aDouble, throwable) -> { System.out.println(aDouble); //do something else }); System.out.println(222); } static CompletableFuture<Double> getPriceAsync() { CompletableFuture<Double> futurePrice = new CompletableFuture<>(); new Thread(() -> { try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } futurePrice.complete(23.55); }).start(); return futurePrice; } }
输出结果:
111
222
23.55
getPriceAsync() 模拟一个很耗时的操作,因为其行为是在一个线程中做的,所以不会阻塞打印 111的程序;
getPriceAsync()中线程在执行完后才会把23.55赋值给futurePrice,所以futurePrice.whenComplete..要等待futurePrice.complete(23.55)执行完才会执行whenComplete。
注意whenComplete内部也是开新的线程执行,所以不会阻塞当前代码,System.out.println(222)会被执行,最后当futurePrice.complete(23.55)执行完后,
System.out.println(aDouble)会执行