1. 创建CompletableFuture对象
CompletableFuture提供了四个静态方法用来创建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)
- runAsync 方法接收的是 Runnable 的实例,意味着它没有返回值
- supplyAsync 方法对应的是有返回值的情况
- 这两个方法的带 executor 的变种,表示让任务在指定的线程池中执行,不指定的话,通常任务是在 ForkJoinPool.commonPool() 线程池中执行的。
2. 返回结果获取
以下4个方法用于获取结果
//同步获取结果
public T get()
public T get(long timeout, TimeUnit unit)
public T getNow(T valueIfAbsent)
public T join()
获取结果时,会阻塞。
getNow有点特殊,如果结果已经计算完则返回结果或者抛出异常,否则返回给定的valueIfAbsent值。
join()与get()区别在于join()返回计算的结果或者抛出一个unchecked异常(CompletionException),而get()返回一个具体的异常.
3.计算结果完成后的回调方法
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action, Executor executor)
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)
上面4个方法是当计算阶段结束的时候触发。可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。BiConsumer有两个入参,分别代表计算返回值,另外一个是异常。
whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行,也就是可能是其他线程来执行。
示例
public static void whenComplete() throws Exception {
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
}
if(new Random().nextInt()%2>=0) {
int i = 12/0;
}
System.out.println("run end ...");
});
future.whenComplete(new BiConsumer<Void, Throwable>() {
@Override
public void accept(Void t, Throwable action) {
System.out.println("执行完成!");
}
});
//以下是lamda表达式的写法
/*
future.whenComplete((v,e)->{
System.out.println("执行完成!");
});
*/
future.exceptionally(new Function<Throwable, Void>() {
@Override
public Void apply(Throwable t) {
System.out.println("执行失败!"+t.getMessage());
return null;
}
});
TimeUnit.SECONDS.sleep(2);
}
4.让线程串行执行的三个方法thenRun、thenAccept、thenApply
当计算结算完成之后,后面可以接继续一系列的thenXX,来完成值的转化或下一步执行.
- thenRun:前一个线程执行完后执行thenRun,不需要依赖前一个线程的结果并且没有返回值
- thenAccept:前一个线程执行完后执行thenAccept,需要依赖前一个线程的结果,但是没有返回值
- thenApply:前一个线程执行完后执行thenApply,需要依赖前一个线程的结果,并有返回值
源码方法定义
thenRun
public CompletableFuture<Void> thenRun(Runnable action);
public CompletableFuture<Void> thenRunAsync(Runnable action);
public CompletableFuture<Void> thenRunAsync(Runnable action,Executor executor) ;
thenAccept
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)
T:为上一个线程执行的结果类型
thenApply
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)
T:上一个任务返回结果的类型
U:当前任务的返回值类型
示例
CompletableFuture.runAsync(() -> {
}).thenRun(()