Future优点
Future优点在于咱们能够异步地进行一些十分密布的计算,而不会堵塞当前的线程,这样,咱们在此期间就能够做一些其他的作业。
但是,当获取成果的时分,future想要获取成果的时分,会在主线程中堵塞住。一起,考虑下多个 Future的场景。如果咱们有多了 Future,并且这些 Future之间产生联系。
-
场景1:第一个 Future 的回来值是第二个 Future 的输入
-
场景2:创立三个 Future,f1需求20s,f2需求5s,f3需求10s,然后咱们将他们
list.add(f1);list.add(f2);list.add(f3)
,再依次fx.get()
,你会发现,即便f2先执行完,也要等f1执行完,f2.get
才能回来。
- CompeletionService处理了这个缺陷,拜见呵呵,面试官问我知不知道CompletionService?
下面罗列了 Future 几个缺陷:
Future缺陷
-
Future.get办法尽管能够设置超时时刻,但是在超时时刻到来前无法手动完毕或完结
-
Future provides a get() method which blocks until the result is available. further action can not be performed on a Future’s result without blocking the primary application thread Future.get()办法是堵塞的,直到有回来值回来。也就是说在不堵塞主应用程序线程的情况下,无法对 Future 的成果执行进一步的操作
-
Asynchronous workflows can not be created by chaining multiple Futures together. 多个 Future 不能链(chain)在一起来创立异步作业流
-
Futures which are running in parallel, can not be combined together. 并行运转的 Future 不能合并在一起
-
Future API does not have any exception handling construct. Future API 没有反常处理逻辑
举例说明
实例1:stringFuture.get()无法手动停止或完结
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> stringFuture = executor.submit(() -> neverEndingComputation());
System.out.println("The result is: " + stringFuture.get());
如上代码,stringFuture.get()
永久不会有回来值。
实例2: 多个 Future 之间存在依赖联系时
第一个 Future 的回来值是第二个 Future 的输入,代码如下:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> firstApiCallResult = executor.submit(
() -> firstApiCall(someValue)
);
String firstResult = firstApiCallResult.get(); // 主线程堵塞
Future<String> secondApiCallResult = executor.submit(
() -> secondApiCall(firstResult)
);
如上代码,能够看到,第二个 Future 需求等候第一个 Future的回来值,并且第一个 Future 的回来值是在主线程中堵塞获取的。
CompletableFuture如何处理Future缺陷的
实例1的答案
针对实例1
的问题,CompletableFuture 如何处理的呢。CompletableFuture 有个 complete(String)办法,他能够手动完毕执行中的使命。回顾下实例1
的代码及 CompletableFuture 的代码
-
实例1
:
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> stringFuture = executor.submit(() -> neverEndingComputation());
System.out.println("The result is: " + stringFuture.get());
- 处理
实例1
问题的代码
CompletableFuture<String> stringCompletableFuture = CompletableFuture.supplyAsync(() -> neverEndingComputation());
stringCompletableFuture.complete("Completed");
System.out.println("Is the stringCompletableFuture done ? " + stringCompletableFuture.isDone());
- result: Is the stringCompletableFuture done ? true
查看下 CompletableFuture.complete(arg)的源码注释就明白了
实例2的答案
实例2
的问题是两个有相关的 Future如何能真实做到异步呢。CompletableFuture的链式(chain)办法就是答案。
实例2
ExecutorService executor = Executors.newSingleThreadExecutor();
Future<String> firstApiCallResult = executor.submit(
() -> firstApiCall(someValue)
);
String firstResult = firstApiCallResult.get(); // 主线程堵塞
Future<String> secondApiCallResult = executor.submit(
() -> secondApiCall(firstResult)
);
- 处理
实例2
问题的代码
var finalResult = CompletableFuture.supplyAsync(
() -> firstApiCall(someValue)
).thenApply(firstApiResult -> secondApiCall(firstApiResult));
能够看到,运用CompletableFuture
链式(chain)办法期间,没有和主线程有任何交互。更进一步,你能够在每个链式(chain)办法中打印下线程名
,你会发现都不是主线程名。也就是说,CompletableFuture
链式(chain)办法彻底做到了全程无堵塞。
能够看到,CompletableFuture 与 Java Streams 十分类似。
it`s time to summary
CompletableFuture
处理了 Future
在多个 Future
有相关的场景下的缺乏。一起,CompletableFuture
也能够主动/手动去完毕/完结异步使命。并且,CompletableFuture
供给了十分丰富的办法。
参考:java-completablefuture