Files
rikako-note/java se/CompletableFuture.md

115 lines
6.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CompletableFuture
对于Future对象需要调用其get方法来获取值get方法会阻塞当前线程直到该值可获取。
而CompletableFuture实现了Future接口并且其提供了其他机制来获取result。通过CompletableFuture可以注册一个callback该回调会在result可获取时调用。
```java
CompletableFuture<String> f = . . .;
f.thenAccept(s -> Process the result string s);
```
**通过这种方法就无需等待result处于可获取状态之后再对其进行处理。**
通常情况下很少有方法返回类型为CompletableFuture此时需要自己指定返回类型。CompletableFuture使用方法如下
```java
public CompletableFuture<String> readPage(URL url)
{
return CompletableFuture.supplyAsync(() ->
{
try
{
return new String(url.openStream().readAllBytes(), "UTF-8");
}
catch (IOException e)
{
throw new UncheckedIOException(e);
}
}, executor);
}
```
> Compatable.supplyAsync方法接受一个Supplier而不是一个Callable虽然它们都没有参数且返回一个T但是Callable允许抛出Exception但Supplier不许抛出Checked Exception。
> 并且,**再没有显式为supplyAsync方法指定Executor参数时其会默认采用ForkJoinPool.commonPool()**
Complatable可以以两种方式执行结束1是否有返回值2是否有未捕获异常。要处理以上两种情况需要使用whenComplete方法。提供给whenComplete函数的方法将会和执行result如果没有返回值则为null与抛出异常exception如果没有则为null一起被调用。
```java
f.whenComplete((s, t) -> {
if (t == null)
{
Process the result s;
}
else
{
Process the Throwable t;
}
});
```
CompletableFuture可以手动设置completable value。虽然CompletableFuture对象的完成状态在supplyAsync方法的task执行结束之后会被隐式设置为已完成但是通过手动设置完成状态可以提供更大的灵活性例如可以同时以两种方式进行计算任一方式先计算结束则将CompletableFuture对象的完成状态设置为已完成
```java
var f = new CompletableFuture<Integer>();
executor.execute(() ->
{
int n = workHard(arg);
f.complete(n);
});
executor.execute(() ->
{
int n = workSmart(arg);
f.complete(n);
});
```
如果想要以抛出异常的方式将CompletableFuture对象的完成状态设置为已完成可以调用completeExcetpionally方法
```java
Throwable t = . . .;
f.completeExceptionally(t);
```
> 在不同的线程中调用同一个对象的complete或completeExceptionally方法是线程安全的如果该completableFuture对象的完成状态为已完成那么再次调用complete或completeExceptionally方法无效。
> ## Caution
> 并不像Future对象CompletableFuture对象在调用其cancel方法时并不会对其task执行的线程进行中断操作而是**仅仅将completableFuture对象的完成状态设置为抛出CancellationException的已完成状态。**
> 因为对于一个CompletableFuture对象可能并没有一个唯一的线程对应其task的执行future对象对应task可能未在任何线程中执行也可能在多个线程中执行
## CompletableFuture组合
异步方法的非阻塞调用是通过callback来实现的调用者注册一个action该action在task被完成时调用。如果注册的action仍然是异步的那么该action的下一个action位于另一个完全不同的callback中。
```java
f1.whenComplete((s,t)->{
CompletableFuture<> f2 = ...
f2.whencomplete((s,t)->{
//...
})
})
```
这样可能会造成callback hell的情况并且异常处理也特别不方便由此CompletableFuture提供了一种机制来组合多个CompletableFuture
```java
CompletableFuture<String> contents = readPage(url);
CompletableFuture<List<URL>> imageURLs =
contents.thenApply(this::getLinks);
```
在completableFuture对象上调用thenApply方法thenApply方法也不会阻塞其会返回另一个completableFuture对象并且当第一个Future对象contents返回之后返回结果会填充到getLinks方法的参数中。
### CompletableFuture常用方法
CompletableFuture组合可以有如下常用方法
- thenApplyT -> U)对CompletableFuture对象的返回结果执行操作并且产生一个返回值
- thenAccept(T -> void)类似thenApply操作上一个future的返回值但是返回类型为void
- handle(T,Throwable)->U处理上一个future返回的result并且产生一个返回值
- thenCompose(T->CompletableFuture\<U\>):将上一个Future返回值作为参数传递并且返回CompletableFuture\<U\>
- whenCompleteT,Throwable->void类似于handle但是不产生返回值
- exceptionallyThrowable->T):处理异常并返回一个结果
- completeOnTimeoutT,long,TimeUnit)当超时时将传入的参数T作为返回结果
- orTimeOutlong,TimeUnit)当超时时产生一个TimeoutExcetpion作为结果
- thenRunRunnable:执行该Runnable并且返回一个CompletableFuture<void>
如上的每一个方法都有另一个Async版本如thenApplyAsync
```java
CompletableFuture<U> future.thenApply(f);
CompletableFuture<U> future.thenApplyAsync(f);
```
thenApply中会对future的返回结果执行f操作而在thenApplyAsync中对f操作的执行会在另一个线程中。
thenCompose通常用来连接两个返回类型都为CompletableFuture的方法。
### CompletableFuture Combine
- thenCombine(CompletableFuture\<U\>,(T,U)->V):执行两个future并且通过f对两个future的返回值进行combine
- thenAcceptBoth(CompletableFuture\<U\>,(T,U)->Void):执行两个future并通过f处理两个future的返回值但是返回类型为void
- runAfterBothCompletableFuture\<\>,Runnable当两个future都执行完之后执行Runnable
- applyToEither(CompletableFuture\<T\>T-> U)当任一future执行完成通过该result产生返回值
- acceptEitherCompletableFuture\<T\>T->Void):类似applyToEither但是返回值为void
- runAfterEitherCompletableFuture\<\>,Runnable在任一future执行完成之后执行Runnable
- static allOf(CompletableFuture\<?\>...)在参数中所有future执行完成之后返回的future处于完成状态
- static anyOf(CompletableFuture\<?\>...)在参数中任一future执行完成之后返回的future处于完成状态
### completedFuture
CompletableFuture.completedFuture会返回一个已经执行完成的CompletableFuture对象并且该future对象返回值为T