type
status
date
slug
summary
tags
category
icon
password
为什么要有CompletableFuture
future 接口定义了操作异步任务执行的一些方法,如获取异步任务的执行结果,取消任务执行,判断任务是否被取消,判断任务执行是否完毕等。

image-20230625103629264
它可以为主线程开一个分支任务,一般使用他的实现类 FutureTask 异步任务。
异步多线程任务执行且返回有结果,有三个特点:多线程/有返回/异步任务
可以实现 runnable 接口和 Callable 接口,但是 runnable接口不支持返回值,callable 接口虽然有返回值,异步执行的时候不能中断等各种操作。
而 FutureTask 满足所有
结果

image-20230625112154628
优缺点
上面是 Future 的实现类 FutureTask,看起来还可以,那为什么要演化为 CompletableFuture,Future有什么不足,CompletableFuture又进行了什么改进?
- 优点:Future+线程池异步多线程任务配合,能显著提高程序的运行效率。
- 缺点:
- get()阻塞—一旦调用get()方法求结果,一旦调用不见不散,非要等到结果才会离开,不管你是否计算完成,如果没有计算完成容易程序堵塞。
- isDone()轮询—轮询的方式会耗费无谓的cpu资源,而且也不见得能及时得到计算结果,如果想要异步获取结果,通常会以轮询的方式去获取结果,尽量不要阻塞。
- 结论:Future对于结果的获取不是很友好,只能通过阻塞或轮询的方式得到任务的结果。
代码实现
通过轮询的方式获取任务结果,不让程序阻塞。
这种轮询的方式也只是把等待信息打印出来了,实际上还是在阻塞。
完成一些复杂的任务
- 对于简单的业务场景使用Future完全ok
- 回调通知:
- 应对Future的完成时间,完成了可以告诉我,也就是我们的回调通知
- 通过轮询的方式去判断任务是否完成这样非常占cpu并且代码也不优雅
- 创建异步任务:Future+线程池组合
- 多个任务前后依赖可以组合处理(水煮鱼—>买鱼—>调料—>下锅):
- 想将多个异步任务的结果组合起来,后一个异步任务的计算结果需要钱一个异步任务的值
- 想将两个或多个异步计算合并成为一个异步计算,这几个异步计算互相独立,同时后面这个又依赖前一个处理的结果
- 对计算速度选最快的:
- 当Future集合中某个任务最快结束时,返回结果,返回第一名处理结果
- 结论:
- 使用Future之前提供的那点API就囊中羞涩,处理起来不够优雅,这时候还是让CompletableFuture以声明式的方式优雅的处理这些需求。
- 从i到i++
- Future能干的,CompletableFuture都能干
CompletableFuture对Future的改进
CompletableFuture为什么会出现
get()方法在Future计算完成之前会一直处在阻塞状态下,阻塞的方式和异步编程的设计理念相违背。
- isDene()方法容易耗费cpu资源(cpu空转),
- 对于真正的异步处理我们希望是可以通过传入回调函数,在Future结束时自动调用该回调函数,这样,我们就不用等待结果
jdk8设计出CompletableFuture,CompletableFuture提供了一种观察者模式类似的机制,可以让任务执行完成后通知监听的一方。
get()方法会在 future 计算完成之前会一直处在阻塞状态下,CompletableFuture使用了回调的方法进行获取结果,当运行完成之后主动通知计算结果。
CompletableFuture和CompletionStage介绍
类架构说明:

img
- 接口CompletionStage
- 代表异步计算过程中的某一个阶段,一个阶段完成以后可能会触发另外一个阶段。
- 一个阶段的执行可能是被单个阶段的完成触发,也可能是由多个阶段一起触发
- 类CompletableFuture
- 提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合CompletableFuture的方法
- 它可能代表一个明确完成的Future,也可能代表一个完成阶段(CompletionStage),它支持在计算完成以后触发一些函数或执行某些动作
实现 CompletableFuture
runAsync 无返回值
CompletableFuture优点:
- 异步任务结束时,会自动回调某个对象的方法
- 主线程设置好回调后,不用关心异步任务的执行,异步任务之间可以顺序执行
- 异步任务出错时,会自动回调某个对象的方法