CompletableFuture
为什么会有CompletableFuture
在CompletableFuture未开发出来前,使用Java进行获取异步编程的结果是很不方便的,通常使用Future这个类获取结果,但是是Future是Java 5添加的类,用来描述一个异步计算的结果。你可以使用isDone
方法检查计算是否完成,或者使用get
阻塞住调用线程,直到计算完成返回结果,你也可以使用cancel
方法停止任务的执行。
虽然Future
以及相关使用方法提供了异步执行任务的能力,但是对于结果的获取却是很不方便,只能通过阻塞或者轮询的方式得到任务的结果。阻塞的方式显然和我们的异步编程的初衷相违背,轮询的方式又会耗费无谓的CPU资源,而且也不能及时地得到计算结果,为什么不能用观察者设计模式当计算结果完成及时通知监听者呢?
所以在Java 8中, 新增加了一个包含50个方法左右的类: CompletableFuture,提供了非常强大的Future的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合CompletableFuture的方法。
CompletableFuture实现了Future和CompletionStage两个接口。
Future接口相对简单些,提供了取消(cancel)、获取结果(get)、检测是否完成或者取消(isCancelled、isDone)这些方法,Future接口提供了异步获取结果的能力。但是Future没有提供通知机制,Future是否执行完任务需要不断的检查或者调用get()方法阻塞任务执行,所以CompletableFuture还实现了CompletionStage。CompletionStage相当于阶段,一个CompletionStage对象是异步计算中的一个阶段,当一个CompletionStage完成时会触发下一个动作或计算。前一个任务执行成功后可以自动触发下一个任务的执行,中间无需等待。相当于实现了异步任务的通知机制
CompletableFuture还能够将任务放到不同的线程中执行,既可以在当前线程中直接执行任务,也可以将其放到其他任务线程中执行,这个过程是自动的,无需干预。
使用方法
- CompletableFuture类实现了CompletionStage和Future接口,所以你还是可以像以前一样通过阻塞或者轮询的方式获得结果,尽管这种方式不推荐使用。
public class BasicMain {
public static CompletableFuture<Integer> compute() {
final CompletableFuture<Integer> future = new CompletableFuture<>();
return future;
}
public static void main(String[] args) throws Exception {
final CompletableFuture<Integer> f = compute();
class Client extends Thread {
CompletableFuture<Integer> f;
Client(String threadName, CompletableFuture<Integer> f) {
super(threadName);
this.f = f;
}
@Override
public void run() {
try {
System.out.println(this.getName() + ": " + f.get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
}
new Client("Client1", f).start();
new Client("Client2", f).start();
System.out.println("waiting");
f.complete(100);
//f.completeExceptionally(new Exception());
System.in.read();
// 控制台打印
// waiting
// Client1: 100
// Client2: 100
}
}
可以看到get方法阻塞了client1和client2,当 f.complete(100)计算完成时,client1和client2才输出。
-
CompletableFuture.completedFuture
是一个静态辅助方法,用来返回一个已经计算好的CompletableFuture
。public static <U> CompletableFuture<U> completedFuture(U value)//value就代表线程执行run返回回去的值
创建异步对象
而以下四个静态方法用来为一段异步执行的代码创建CompletableFuture
对象:
public static CompletableFuture<Void> runAsync(Runnable runnable)
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)
以Async
结尾代表异步执行
有没有Executor代表是使用接口提供给的线程池,还是自定义的
Runnable
类型的参数会忽略计算的结果
Supplier
类型类型的参数会返回计算的结果,U代表CompletableFuture
的计算结果类型
异步执行完成的回调
public CompletableFuture<T