CompletableFuture的用法
当我们异步执行一个任务时,一般使用线程池Executor去创建。如果不需要返回值,使用实现Runnable接口的任务;如果需要返回值,使用实现Callable接口的任务,调用Executor的submit方法,再使用Future获取返回值即可。如果多个线程存在依赖组合的化,则可以使用同步组件CountDownLatch、CyclicBarrier等。
CompletableFuture是jdk8的新特性,用于异步编程,CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听方任务的进度,成功或者失败。使用这种方式,主线程不会被阻塞,不需要一直等待子线程完成,从而大大提高程序的性能。
CompletableFuture实现了CompletionStage接口和Future接口。
Future表示异步计算结果。提供了检查计算是否完成、等待计算完成以及获取计算结果的方法。
CompletionStage接口定义了异步计算的某个阶段,它描述了在另一个ComletionStage完成时执行的操作或者是计算值。
使用场景
CompletableFuture提供了包括创建异步任务、任务异步回调、多个任务组合处理等方法,来辅助实现异步任务的处理。
基本用法说明
CompletableFuture提供的方法具有以下特征:
- 方法名不包含
Async,则后续执行的任务或者回调方法和前一个任务在相同线程内按顺序执行 - 方法名包含
Async,则后续执行的任务或者回调方法是异步的,具体分以下情况:Async方法不传入Executor类型参数,则异步执行的任务或者回调方法使用的是默认内置线程池ForkJoinPool.commonPool()Async方法传入自定义的Executor类型参数,则异步执行的任务或者回调方法使用的是自定义的线程池
创建异步任务
| 方法名 | 说明 |
|---|---|
| supplyAsync | 根据Supplier构建有返回值的异步任务 |
| runAsync | 根据Runnable构建无返回值的异步任务 |
任务异步回调
| 方法名 | 说明 | ||
|---|---|---|---|
| thenRun thenRunAsync | 某个任务执行完成后,执行Runnable构建的回调方法 | 前一个任务没有参数传递给回调方法 | 无 |
| thenAccept thenAcceptAsync | 某个任务执行完成后,执行Consumer构建的回调方法 | 前一个任务的返回值作为参数传递给回调方法 | 无 |
| thenApply thenApplyAsync | 某个任务执行完成后,执行Function构建的回调方法 | 前一个任务的返回值作为参数传递给回调方法 | 有 |
| exceptionally | 某个任务执行异常时,执行Function构建的回调方法 | 前一个任务抛出的异常作为参数传递给回调方法。 回调方法和前一个任务在相同线程内按顺序执行。 | 有 |
| whenComplete whenCompleteAsync | 某个任务执行异常时,执行BiConsumer构建的回调方法 | 前一个任务的返回值及抛出的异常(抛出异常时返回值为null)作为参数传递给回调方法 | 无 |
| handle handleAsync | 某个任务执行异常时,执行BiConsumer构建的回调方法 | 前一个任务的返回值及抛出的异常(抛出异常时返回值为null)作为参数传递给回调方法 | 有 |
多个任务组合处理
AND组合关系
| 方法名 | 说明 | ||
|---|---|---|---|
| thenCombine thenCombineAsync | 将两个任务组合起来,只有这两个任务都执行完成之后,才会执行BiFunction构建的回调方法 | 前两个任务的返回值作为参数传递给回调方法 | 有 |
| thenAcceptBoth thenAcceptBothAsync | 将两个任务组合起来,只有这两个任务都执行完成之后,才会执行BiConsumer构建的回调方法 | 前两个任务的返回值作为参数传递给回调方法 | 无 |
| runAfterBoth runAfterBothAsync | 将两个任务组合起来,只有这两个任务都执行完成之后,才会执行Runnable构建的回调方法 | 前两个任务没有参数传递给回调方 | 无 |
OR组合关系
| 方法名 | 说明 | ||
|---|---|---|---|
| applyToEither applyToEitherAsync | 将两个任务组合起来,只要其中一个执行完成了,就会执行Function构建的回调方法 | 已经执行完成的任务返回值作为参数传递给回调方法 | 有 |
| acceptEither acceptEitherAsync | 将两个任务组合起来,只要其中一个执行完成了,就会执行Consumer构建的回调方法 | 已经执行完成的任务返回值作为参数传递给回调方法 | 无 |
| runAfterEither runAfterEitherAsync | 将两个任务组合起来,只要其中一个执行完成了,就会执行Runnable构建的回调方法 | 没有参数传递给回调方法 | 无 |
allOf
将多个任务组合起来,所有任务都执行完成后,才执行allOf返回的CompletableFuture
anyOf
将多个任务组合起来,任意一个任务执行完成后,就会执行anyOf返回的CompletableFuture
thenCompose/thenComposeAsync
- 某个任务执行完成后,执行
Function构建的回调方法 - 前一个任务的返回值作为参数传递给回调方法
- 回调方法返回一个新的
CompletableFuture
获取返回值
get()/get(long, TimeUnit)
- 等待任务执行完成后获取返回值,根据任务执行情况可能抛出
ExecutionException、InterruptedException等异常 get()方法是阻塞的,一般使用get(long, TimeUnit)设置超时时间
join()
- 完成后返回结果值,当任务执行出现未经检查的异常时,则默认使用
CompletionException对异常进行包装后再抛出
注意事项
ForkJoinPool.commonPool()线程池,处理的线程个数是CPU核数 - 1。在大量请求,并且任务的处理逻辑比较复杂耗时的话,响应会很慢,此时建议使用自定义线程池,配置合适的线程池参数。
对比parallelStream并行流
CompletableFuture可以控制线程池的线程数量,如果执行的任务是IO密集星的,应该使用CompletableFuture。- 如果执行的任务是CPU密集型的,使用比处理器更多的线程是没有意义的,此时使用起来更简单的
parallelStream。
评论区留言准则:
1. 本评论区禁止传播封建迷信、吸烟酗酒、低俗色情、赌博诈骗等任何违法违规内容。
2. 当他人以不正当方式诱导打赏、私下交易,请谨慎判断,以防人身财产损失。
3. 请勿轻信各类招聘征婚、代练代抽、私下交易、购买礼包码、游戏币等广告信息,谨防网络诈骗。