本文参考:https://blog.csdn.net/arjun_yu/article/details/112993354
CompletableFuture
是 Future API
的扩展。
Future 被用于作为一个异步计算结果的引用。提供一个 isDone()
方法来检查计算任务是否完成。当任务完成时,get()
方法用来接收计算任务的结果。
项目需求:
项目中需要优化一个接口,这个接口需要拉取2,3个第三方接口,需求延迟时间小于200ms
;
技术选型:
在Java中CompletableFuture
用于异步编程,异步编程是编写非阻塞的代码,运行的任务在一个单独的线程,与主线程隔离,并且会通知主线程它的进度,成功或者失败。
在这种方式中,主线程不会被阻塞,不需要一直等到子线程完成。主线程可以并行的执行其他任务。使用这种并行方式,可以极大的提高程序的性能。
CompletableFuture
是JDK8
提出的一个支持非阻塞的多功能的Future
,同样也是实现了Future
接口,Future
是Java 5
添加的类,用来描述一个异步计算的结果。java8
对future进一步完善,扩展了诸多功能形成了CompletableFuture
,它拥有Future所有的功能,包括获取异步执行结果,取消正在执行的任务等。
1、CompletableFuture
功能介绍
CompletableFuture
还是一个CompletionStage
。
我们看下CompletableFuture
的定义:
public class CompletableFuture<T> implements Future<T>, CompletionStage<T>
什么是CompletionStage
呢?
在异步程序中,如果将每次的异步执行都看成是一个stage
的话,我们通常很难控制异步程序的执行顺序,在javascript
中,我们需要在回调中执行回调。这就会形成传说中的回调地狱。
好在在ES6
中引入了promise
的概念,可以将回调中的回调转写为链式调用,从而大大的提升了程序的可读性和可写性。
同样的在java
中,我们使用CompletionStage
来实现异步调用的链式操作。CompletionStage
定义了一系列的then***
操作来实现这一功能。
详见:https://segmentfault.com/a/1190000022197398
2、使用CompletableFuture
作为Future
实现
使用无构参构造函数创建此类的实例
CompletableFuture<String> completableFuture = new CompletableFuture<String>();
这是一个最简单的 CompletableFuture
,想获取CompletableFuture
的结果可以使用 CompletableFuture.get()
方法:
String result = completableFuture.get()
get()
方法会一直阻塞直到 Future 完成。因此,以上的调用将被永远阻塞,因为该Future一直不会完成。
另请注意,get方法抛出一些已检查的异常,即
ExecutionException
(封装计算期间发生的异常)和InterruptedException
(表示执行方法的线程被中断的异常)
你可以使用 CompletableFuture.complete()
手工的完成一个 Future:
completableFuture.complete("Future's Result")
所有等待这个 Future 的客户端都将得到一个指定的结果,并且 completableFuture.complete()
之后的调用将被忽略。
public Future<String> calculateAsync() {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
Thread.sleep(500);
completableFuture.complete("Hello");
return null;
});
return completableFuture;
}
这种创建和完成CompletableFuture
的方法可以与任何并发包(包括原始线程)一起使用。
如果你知道执行的结果,那么可以使用CompletableFuture
的completedFuture
方法来直接返回一个Future。
public Future<String> useCompletableFuture(){
Future<String> completableFuture =
CompletableFuture.completedFuture("Hello");
return completableFuture;
}
假设我们没有找到结果并决定完全取消异步执行任务。CompletableFuture
还提供了一个cancel方法来立马取消任务的执行。
public Future<String> calculateAsyncWithCancellation() {
CompletableFuture<String> completableFuture = new CompletableFuture<>();
Executors.newCachedThreadPool().submit(() -> {
Thread.sleep(500);
completableFuture.cancel(false);
return null;
});
return completableFuture;
}
当我们使用
Future.get()
方法阻塞结果时,cancel()
表示取消执行,它将抛出CancellationException
异常。java.util.concurrent.CancellationException
3、异步执行
上面的代码很简单,下面介绍几个 static 方法,它们使用任务来实例化一个 CompletableFuture
实例。
CompletableFuture
提供了runAsync
和supplyAsync
的方法,可以以异步的方式执行代码。
CompletableFuture.runAsync(Runnable runnable);
CompletableFuture.runAsync(Runnable runnable, Executor executor);
CompletableFuture.supplyAsync(Supplier<U> supplier);
CompletableFuture.supplyAsync(Supplier<U> supplier, Executor executor)
这两个方法是executor
的升级,表示让任务在指定的线程池中执行,不指定的话,通常任务是在 ForkJoinPool.commonPool()
线程池中执行的。
3.1、runAsync()
方法接收的是 Runnable 的实例,但是它没有返回值
public void runAsync() {
CompletableFuture.runAsync(() -> {
LOGGER.info("初始化CompletableFuture子任务! runAsync");
}, Executors.newFixedThreadPool(3));
}
3.2、supplyAsync()
方法是JDK8
函数式接口,无参数,会返回一个结果
public void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(new Supplier<String>() {
@Override
public String get() {
LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
}
});
String result = future.get();
LOGGER.info(result);
}
使用lambda表达式使得上面的示例更加简明:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
});
4、转换和运行
对于构建异步系统,我们应该附上一个回调给CompletableFuture
,当Future完成的时候,自动的获取结果。如果我们不想等待结果返回,我们可以把需要等待Future完成执行的逻辑写入到回调函数中。可以使用thenApplyAsync()
, thenAccept()
和thenRun()
方法附上一个回调给CompletableFuture
。
为了控制执行回调任务的线程,你可以使用异步回调。将从
ForkJoinPool.commonPool()
获取不同的线程执行。此外,如果你传入一个Executor
到thenApplyAsync()
回调中,,任务将从Executor线程池获取一个线程执行。
4.1、 thenApplyAsync()
在两个任务任务A,任务B中,任务B想要任务A计算的结果,可以用thenApplyAsync
方法来接受一个函数实例,用它来处理结果,并返回一个Future函数的返回值:
模板
CompletableFuture.runAsync(() -> {}).thenApply(resultA -> "resultB");
CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB");
任务 A 执行完执行 B,B 需要 A 的结果,同时任务 B 有返回值。
多个任务的情况下,如果任务 B 后面还有任务 C,往下继续调用.thenApplyAsync()
即可。
实战
public void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
});
CompletableFuture<String> completableFuture = future.thenApplyAsync(resultA -> {
LOGGER.info(resultA);
return "Hello " + resultA;
}).thenApplyAsync(resultB -> {
LOGGER.info(resultB);
return resultB + ", Welcome to the arjun Blog";
});
System.out.println(completableFuture.get());
// Prints - Hello Result of the asynchronous computation, Welcome to the arjun Blog
}
4.2、thenAcceptAsync()
在两个任务任务A,任务B中,如果你不需要在Future中有返回值,则可以用 thenAcceptAsync
方法接收将计算结果传递给它。最后的future.get()
调用返回Void类型的实例。CompletableFuture.thenAcceptAsync()
持有一个Consumer<T>
,返回一个CompletableFuture<Void>
。它可以访问CompletableFuture
的结果:
模板
CompletableFuture.runAsync(() -> {}).thenAccept(resultA -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {});
-
runAsync
不会有返回值,方法thenAcceptAsync
,接收到的resultA
值为null,同时任务B也不会有返回结果 -
supplyAsync
有返回值,同时任务B不会有返回结果。
实战
public void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
});
CompletableFuture<Void> completableFuture = future.thenAcceptAsync(resultA -> {
LOGGER.info("Computation returned: {}", resultA);
});
System.out.println(completableFuture.get());
// Prints - null
}
4.3、thenRunAsync()
如果你不想从你的回调函数中返回任何东西,仅仅想在Future完成后运行一些代码片段,你可以使用thenAcceptAsync()
和 thenRunAsync()
方法,这些方法经常在调用链的最末端的最后一个回调函数中使用。thenRun()
不能访Future的结果,它持有一个Runnable返回CompletableFuture<Void>
:
模板
CompletableFuture.runAsync(() -> {}).thenRun(() -> {});
CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {});
-
runAsync
不会有返回值,方法thenRunAsync(Runnable runnable)
,任务 A 执行完执行 B,并且 B 不需要 A 的结果。 -
supplyAsync
有返回值,方法thenRunAsync(Runnable runnable)
,任务 A 执行完执行 B,会返回resultA
,但是 B 不需要 A 的结果。
实战
public void supplyAsync() throws ExecutionException, InterruptedException {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
LOGGER.info("初始化CompletableFuture子任务! supplyAsync");
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of the asynchronous computation";
});
CompletableFuture<Void> completableFuture = future.thenRunAsync(() -> System.out.println("Computation finished."));
// Prints - Computation finished.
System.out.println(completableFuture.get());
// Prints - null
}
5、组合Futures
上面讲到CompletableFuture
的一个重大作用就是将回调改为链式调用,从而将Futures组合起来。
5.1. 使用 thenCompose()
组合两个独立的future
thenCompose
将前一个Future的返回结果作为后一个操作的输入。
模板
CompletableFuture<String> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " World"));
实战
假设你想从一个远程API
中获取一个用户的详细信息,一旦用户信息可用,你想从另外一个服务中获取他的贷方。
考虑下以下两个方法getUserDetail()
和getCreditRating()
的实现:
CompletableFuture<User> getUsersDetail(String userId) {
return CompletableFuture.supplyAsync(() -> {
UserService.getUserDetails(userId);
});
}
CompletableFuture<Double> getCreditRating(User user) {
return CompletableFuture.supplyAsync(() -> {
CreditRatingService.getCreditRating(user);
});
}
现在让我们弄明白当使用了thenApply()
后是否会达到我们期望的结果?
CompletableFuture<CompletableFuture<Double>> result = getUsersDetail(userId)
.thenApply(user -> getCreditRating(user));
在以上
thenApply
的示例中,Supplier
函数传入thenApply
将返回一个简单的值,但是在本例中,将返回一个CompletableFuture
。以上示例的最终结果是一个嵌套的CompletableFuture
。
如果你想获取最终的结果给最顶层future,使用thenCompose()
方法代替
CompletableFuture<Double> result = getUsersDetail(userId)
.thenCompose(user -> getCreditRating(user));
因此,规则就是-如果你的回调函数返回一个
CompletableFuture
,但是你想从CompletableFuture
链中获取一个直接合并后的结果,这时候你可以使用thenCompose()
。因此,如果想要继续嵌套链接CompletableFuture
方法,那么最好使用thenCompose()
。
thenApply()
和thenCompose()
之间的区别
该
thenCompose()
方法类似于thenApply()
在都返回一个新的计算结果。但是,thenCompose()
使用前一个Future作为参数。它会直接使结果变新的Future,而不是我们在thenApply()
中到的嵌套Future,而是用来连接两个CompletableFuture
,是生成一个新的CompletableFuture
:
5.2、使用thenCombine()
组合两个独立的 future
如果要执行两个独立的任务,并对其结果执行某些操作,可以用Future的thenCombine
方法。被用来当两个独立的Future
都完成的时候,用来做一些事情。
模板
CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> "resultA");
CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> "resultB");
cfA.thenAcceptBoth(cfB, (resultA, resultB) -> {});
cfA.thenCombine(cfB, (resultA, resultB) -> "result A + B");
实战
System.out.println("Retrieving weight.");
CompletableFuture<Double> weightInKgFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return 65.0;
});
System.out.println("Retrieving height.");
CompletableFuture<Double> heightInCmFuture = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return 177.8;
});
System.out.println("Calculating BMI.");
CompletableFuture<Double> combinedFuture = weightInKgFuture
.thenCombine(heightInCmFuture, (weightInKg, heightInCm) -> {
Double heightInMeter = heightInCm/100;
return weightInKg/(heightInMeter*heightInMeter);
});
System.out.println("Your BMI is - " + combinedFuture.get());
当两个Future都完成的时候,传给
thenCombine()
的回调函数将被调用。
5.3、使用thenAcceptBoth()
组合两个独立的 future
更简单的情况是,当你想要使用两个Future结果时,但不需要将任何结果值进行返回时,可以用thenAcceptBoth
,它表示后续的处理不需要返回值,而 thenCombine
表示需要返回值:
如果你不想返回结果,则可以使用thenAcceptBoth
:
CompletableFuture<Void> completableFuture = CompletableFuture.supplyAsync(() -> "Hello")
.thenAcceptBoth(CompletableFuture.supplyAsync(() -> " World"), (s1, s2) -> System.out.println(s1 + s2));
6、并行运行多个任务
我们使用thenCompose()
和 thenCombine()
把两个CompletableFuture
组合在一起。当我们需要并行执行多个任务时,我们通常希望等待所有它们执行,然后处理它们的组合结果。现在如果你想组合任意数量的CompletableFuture
,应该怎么做?
我们可以使用以下两个方法组合任意数量的CompletableFuture
。
API
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs){...}
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs){...}
6.1、CompletableFuture.allOf()
该CompletableFuture.allOf
静态方法允许等待所有的完成任务:
CompletableFuture.allOf
的使用场景是当你一个列表的独立future,并且你想在它们都完成后并行的做一些事情。
实战场景
假设你想下载一个网站的100个不同的页面。你可以串行的做这个操作,但是这非常消耗时间。因此你想写一个函数,传入一个页面链接,返回一个CompletableFuture
,异步的下载页面内容。
CompletableFuture<String> downloadWebPage(String pageLink) {
return CompletableFuture.supplyAsync(() -> {
// TODO Code to download and return the web page's content
});
}
现在,当所有的页面已经下载完毕,你想计算包含关键字CompletableFuture
页面的数量。可以使用CompletableFuture.allOf()
达成目的。
List<String> webPageLinks = Arrays.asList(...) // A list of 100 web page links
// Download contents of all the web pages asynchronously
List<CompletableFuture<String>> pageContentFutures = webPageLinks.stream()
.map(webPageLink -> downloadWebPage(webPageLink))
.collect(Collectors.toList());
// Create a combined Future using allOf()
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
pageContentFutures.toArray(new CompletableFuture[pageContentFutures.size()])
);
使用CompletableFuture.allOf()
的问题是它返回CompletableFuture<Void>
。这种方法的局限性在于它不会返回所有任务的综合结果。相反,你必须手动从Futures获取结果。幸运的是,CompletableFuture.join()
方法和Java 8 Streams API
可以解决:
// When all the Futures are completed, call `future.join()` to get their results and collect the results in a list -
CompletableFuture<List<String>> allPageContentsFuture = allFutures.thenApply(v -> {
return pageContentFutures.stream()
//.map(pageContentFuture -> pageContentFuture.join())
.map(CompletableFuture::join)
.collect(Collectors.toList());
});
CompletableFuture
提供了 join() 方法,它的功能和 get() 方法是一样的,都是阻塞获取值,它们的区别在于 join() 抛出的是 unchecked Exception。这使得它可以在Stream.map()
方法中用作方法引用。
现在让我们计算包含关键字页面的数量。
// Count the number of web pages having the "CompletableFuture" keyword.
CompletableFuture<Long> countFuture = allPageContentsFuture.thenApply(pageContents -> {
return pageContents.stream()
.filter(pageContent -> pageContent.contains("CompletableFuture"))
.count();
});
System.out.println("Number of Web Pages having CompletableFuture keyword - " + countFuture.get());
6.2、CompletableFuture.anyOf()
CompletableFuture.anyOf()
和其名字介绍的一样,当任何一个CompletableFuture
完成的时候【相同的结果类型】,返回一个新的CompletableFuture
。
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of Future 1";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of Future 2";
});
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
return "Result of Future 3";
});
CompletableFuture<Object> anyOfFuture = CompletableFuture.anyOf(future1, future2, future3);
System.out.println(anyOfFuture.get());
// Prints - Result of Future 2
在以上示例中,当三个中的任何一个
CompletableFuture
完成,anyOfFuture
就会完成。因为future2
的休眠时间最少,因此它最先完成,最终的结果将是future2
的结果。
CompletableFuture.anyOf()
传入一个Future可变参数,返回CompletableFuture<Object>
。CompletableFuture.anyOf()
的问题是如果你的CompletableFuture
返回的结果是不同类型的,这时候你讲会不知道你最终CompletableFuture
是什么类型。
7、异常处理
我们探寻了怎样创建CompletableFuture,转换它们,并组合多个CompletableFuture。现在让我们弄明白当发生错误的时候我们应该怎么做。
首先让我们明白在一个回调链中错误是怎么传递的。思考下以下回调链:
CompletableFuture.supplyAsync(() -> {
// Code which might throw an exception
return "Some result";
}).thenApply(result -> {
return "processed result";
}).thenApply(result -> {
return "result after further processing";
}).thenAccept(result -> {
// do something with the final result
});
如果在原始的supplyAsync()
任务中发生一个错误,这时候没有任何thenApply
会被调用并且future将以一个异常结束。如果在第一个thenApply
发生错误,这时候第二个和第三个将不会被调用,同样的,future将以异常结束。
7.1、使用 exceptionally() 回调处理异常
exceptionally()
回调给你一个从原始Future中生成的错误恢复的机会。你可以在这里记录这个异常并返回一个默认值。
API
public CompletableFuture<T> exceptionally(Function<Throwable, ? extends T> fn);
看下代码
CompletableFuture.supplyAsync(() -> "resultA")
.thenApply(resultA -> resultA + " resultB")
.thenApply(resultB -> resultB + " resultC")
.thenApply(resultC -> resultC + " resultD");
上面的代码中,任务 A、B、C、D 依次执行,如果任务 A 抛出异常(当然上面的代码不会抛出异常),那么后面的任务都得不到执行。如果任务 C 抛出异常,那么任务 D 得不到执行。
那么我们怎么处理异常呢?看下面的代码,我们在任务 A 中抛出异常,并对其进行处理:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException();
})
.exceptionally(ex -> "ERROR - ResultA")
.thenApply(resultA -> resultA + ", resultB")
.thenApply(resultB -> resultB + ", resultC")
.thenApply(resultC -> resultC + ", resultD");
System.out.println(future.join());
// Prints - ERROR - ResultA, resultB, resultC, resultD
上面的代码中,任务 A 抛出异常,然后通过
.exceptionally()
方法处理了异常,并返回新的结果,这个新的结果将传递给任务 B。
实战情景
Integer age = -1;
CompletableFuture<String> maturityFuture = CompletableFuture.supplyAsync(() -> {
if(age < 0) {
throw new IllegalArgumentException("Age can not be negative");
}
if(age > 18) {
return "Adult";
} else {
return "Child";
}
}).exceptionally(ex -> {
LOGGER.error("Oops! We have an exception - {}", ex.getMessage());
return "Unknown!";
});
System.out.println("Maturity : " + maturityFuture.get());
// Prints - Maturity : Unknown!
7.2、使用 handle() 方法处理异常
API
提供了一个更通用的方法 - handle()
从异常恢复,无论一个异常是否发生它都会被调用。
API
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
如果在链式调用的时候抛出异常,则可以在最后使用handle来接收。
public void handleError() throws ExecutionException, InterruptedException {
String name = null;
CompletableFuture<String> completableFuture
= CompletableFuture.supplyAsync(() -> {
if (name == null) {
throw new RuntimeException("Computation error!");
}
return "Hello, " + name;
}).handle((res, ex) -> res != null ? res : "Hello, Stranger!");
System.out.println(completableFuture.get());
// Prints - Hello, Stranger!
}
实战情景
Integer age = -1;
CompletableFuture<String> maturityFuture = CompletableFuture.supplyAsync(() -> {
if(age < 0) {
throw new IllegalArgumentException("Age can not be negative");
}
if(age > 18) {
return "Adult";
} else {
return "Child";
}
}).handle((res, ex) -> {
if(ex != null) {
LOGGER.error("Oops! We have an exception - {}", ex.getMessage());
return "Unknown!";
}
return res;
});
System.out.println("Maturity : " + maturityFuture.get());
// Prints - Maturity : Unknown!
如果异常发生,
res
参数将是 null,否则,ex
将是 null。
7.3、使用whenComplete()
方法处理异常
API
public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action);
返回传进去的值
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// long running task
throw new RuntimeException("error!");
});
future.whenComplete((result, exception) -> {
if (null == exception) {
System.out.println("result from previous task: " + result);
} else {
System.err.println("Exception thrown from previous task: " + exception.getMessage());
}
});
exceptionally()
的使用非常类似于try{}catch{}
中的catch{}
,但是由于支持链式编程方式,所以相对更简单。
whenComplete()
和handle()
系列方法就类似于try{}finally{}
中的finally{}
,无论是否发生异常都会执行whenComplete()
中的回调函数BiConsumer
和handle()
中的回调函数BiFunction
。顾名思义,BiConsumer
是直接消费的,而BiFunction
是有返回值的,
whenComplete()
和handle()
的区别在于whenComplete()
不支持返回结果,而handle()
是支持返回结果的。
8、Async
后缀方法
CompletableFuture
类中的API
的大多数方法都有两个带有Async
后缀的附加修饰。这些方法表示用于异步线程。
没有Async
后缀的方法使用调用线程运行下一个执行线程阶段。不带Async
方法使用ForkJoinPool.commonPool()
线程池的fork / join
实现运算任务。带有Async
方法使用传递式的Executor任务去运行。
9、JDK 9 CompletableFuture API
在Java 9
中, CompletableFuture API
通过以下更改得到了进一步增强:
- 新工厂方法增加了
- 支持延迟和超时
- 改进了对子类化的支持。
引入了新的实例API
:
Executor defaultExecutor()
CompletableFuture<U> newIncompleteFuture()
CompletableFuture<T> copy()
CompletionStage<T> minimalCompletionStage()
CompletableFuture<T> completeAsync(Supplier<? extends T> supplier, Executor executor)
CompletableFuture<T> completeAsync(Supplier<? extends T> supplier)
CompletableFuture<T> orTimeout(long timeout, TimeUnit unit)
CompletableFuture<T> completeOnTimeout(T value, long timeout, TimeUnit unit)
还有一些静态实用方法:
Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
Executor delayedExecutor(long delay, TimeUnit unit)
<U> CompletionStage<U> completedStage(U value)
<U> CompletionStage<U> failedStage(Throwable ex)
<U> CompletableFuture<U> failedFuture(Throwable ex)
最后,为了解决超时问题,Java 9
又引入了两个新功能:
orTimeout()
completeOnTimeout()