diff --git a/java se/CompletableFuture.md b/java se/CompletableFuture.md new file mode 100644 index 0000000..60415b9 --- /dev/null +++ b/java se/CompletableFuture.md @@ -0,0 +1,114 @@ +# CompletableFuture +对于Future对象,需要调用其get方法来获取值,get方法会阻塞当前线程直到该值可获取。 +而CompletableFuture实现了Future接口,并且其提供了其他机制来获取result。通过CompletableFuture可以注册一个callback,该回调会在result可获取时调用。 +```java +CompletableFuture f = . . .; +f.thenAccept(s -> Process the result string s); +``` +**通过这种方法,就无需等待result处于可获取状态之后再对其进行处理。** +通常情况下,很少有方法返回类型为CompletableFuture,此时,需要自己指定返回类型。CompletableFuture使用方法如下: +```java +public CompletableFuture 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(); +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 contents = readPage(url); +CompletableFuture> imageURLs = +contents.thenApply(this::getLinks); +``` +在completableFuture对象上调用thenApply方法,thenApply方法也不会阻塞,其会返回另一个completableFuture对象,并且,当第一个Future对象contents返回之后,返回结果会填充到getLinks方法的参数中。 +### CompletableFuture常用方法 +CompletableFuture组合可以有如下常用方法: +- thenApply(T -> U):对CompletableFuture对象的返回结果执行操作,并且产生一个返回值 +- thenAccept(T -> void):类似thenApply,操作上一个future的返回值,但是返回类型为void +- handle(T,Throwable)->U:处理上一个future返回的result并且产生一个返回值 +- thenCompose(T->CompletableFuture\):将上一个Future返回值作为参数传递,并且返回CompletableFuture\ +- whenComplete(T,Throwable)->void:类似于handle,但是不产生返回值 +- exceptionally(Throwable->T):处理异常并返回一个结果 +- completeOnTimeout(T,long,TimeUnit):当超时时,将传入的参数T作为返回结果 +- orTimeOut(long,TimeUnit):当超时时,产生一个TimeoutExcetpion作为结果 +- thenRun(Runnable):执行该Runnable并且返回一个CompletableFuture +如上的每一个方法都有另一个Async版本,如thenApplyAsync: +```java +CompletableFuture future.thenApply(f); +CompletableFuture future.thenApplyAsync(f); +``` +thenApply中,会对future的返回结果执行f操作;而在thenApplyAsync中,对f操作的执行会在另一个线程中。 +thenCompose通常用来连接两个返回类型都为CompletableFuture的方法。 + +### CompletableFuture Combine +- thenCombine(CompletableFuture\,(T,U)->V):执行两个future,并且通过f对两个future的返回值进行combine +- thenAcceptBoth(CompletableFuture\,(T,U)->Void):执行两个future,并通过f处理两个future的返回值,但是返回类型为void +- runAfterBoth(CompletableFuture\<?\>,Runnable):当两个future都执行完之后,执行Runnable +- applyToEither(CompletableFuture\,(T)-> U):当任一future执行完成,通过该result产生返回值 +- acceptEither(CompletableFuture\,T->Void):类似applyToEither,但是返回值为void +- runAfterEither(CompletableFuture\<?\>,Runnable):在任一future执行完成之后,执行Runnable +- static allOf(CompletableFuture\...):在参数中所有future执行完成之后,返回的future处于完成状态 +- static anyOf(CompletableFuture\...):在参数中任一future执行完成之后,返回的future处于完成状态 + +### completedFuture +CompletableFuture.completedFuture会返回一个已经执行完成的CompletableFuture对象,并且该future对象返回值为T