Java 8 中, 新增加了一个包含 50 个方法左右的类–CompletableFuture,它提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,并且提供了函数式编程的能力,可以通过回调的方式处理计算结果,也提供了转换和组合 CompletableFuture 的方法。
优点
我们可以不用再去手工维护线程,任务分配的工作我们不再关注。
语义清晰,只用专注业务逻辑。
// two任务有返回值, one任务没有返回值
// 聚合and ,只有one和two都执行完毕才会执行three任务
CompletableFuture<Void> one = CompletableFuture.runAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务1");
});
CompletableFuture<String> two = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务2");
return "world";
});
CompletableFuture<String> three = one.thenCombine(two, (s, tf) -> {
System.out.println(s);
System.out.println("任务3" + tf);
return tf + "123";
});
System.out.println(three.join());
创建
runAsync方法不支持返回值,supplyAsync支持返回值,他们也都执行自己指定的线程池。如果不指定的话, 它们都是用的一个线程池ForkJoinPool。默认线程数为CPU的核数。我们一定要根据不同业务类型创建不同线程池。
创建完成CompletableFuture对象后,会自动异步的执行runnable.run方法或者supplier.get方法。对于一个异步操作,我们只需要关心1.异步什么时候结束,2.如何获取异步执行的结果。
CompletionStage提供了40多种方法,用于表示任务与任务之间的关系。
1.串行关系,主要是thenApply、thenAccept、thenRun和thenCompose这四 个系列的接口。
//支持返回值和入参
public <U> CompletableFuture<U> thenApply(
Function<? super T,? extends U> fn) {
return uniApplyStage(null, fn);
}
//支持入参
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
return uniAcceptStage(null, action);
}
//不接受入参,也不接受返回值
public CompletableFuture<Void> thenRun(Runnable action) {
return uniRunStage(null, action);
}
CompletableFuture<String> f0 =
CompletableFuture.supplyAsync(
() -> "Hello World") //1 .thenApply(s -> s + " QQ") //2 .thenApply(String::toUpperCase);//3
System.out.println(f0.join()); //输出结果
HELLO WORLD QQ
- 描述AND汇聚关系
CompletionStage接口里面描述AND汇聚关系,主要是thenCombine、thenAcceptBoth和runAfterBoth系列的接口.
public <U,V> CompletableFuture<V> thenCombine(
CompletionStage<? extends U> other,
BiFunction<? super T,? super U,? extends V> fn) {
return biApplyStage(null, other, fn);
}
public <U> CompletableFuture<Void> thenAcceptBoth(
CompletionStage<? extends U> other,
BiConsumer<? super T, ? super U> action) {
return biAcceptStage(null, other, action);
}
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
Runnable action) {
return biRunStage(null, other, action);
}
3.OR汇聚关系
public <U> CompletableFuture<U> applyToEither(
CompletionStage<? extends T> other, Function<? super T, U> fn) {
return orApplyStage(null, other, fn);
}
public CompletableFuture<Void> acceptEither(
CompletionStage<? extends T> other, Consumer<? super T> action) {
return orAcceptStage(null, other, action);
}
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
Runnable action) {
return orRunStage(null, other, action);
}
4.异常处理
上面的方法都不允许抛出可检查异常,但我们无法限制它抛出运行时异常,因此提供了方法。
//catch
public CompletableFuture<T> exceptionally(
Function<Throwable, ? extends T> fn) {
return uniExceptionallyStage(fn);
}
//finally
public CompletableFuture<T> whenComplete(
BiConsumer<? super T, ? super Throwable> action) {
return uniWhenCompleteStage(null, action);
}
//finally
public <U> CompletableFuture<U> handle(
BiFunction<? super T, Throwable, ? extends U> fn) {
return uniHandleStage(null, fn);
}
exceptionally()的使用非常类似于 try{}catch{}中的catch{},但是由于支持链式编程方式,所以相对更简单。既然有try{}catch{},那就一定还 有try{}finally{},whenComplete()和handle()系列方法就类似于try{}finally{}中的finally{},无论是否发生异 常都会执行whenComplete()中的回调函数consumer和handle()中的回调函数fn。whenComplete()和 handle()的区别在于whenComplete()不支持返回结果,而handle()是支持返回结果的。