1. 业务场景:
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间。

假如商品详情页的每个查询,需要如下标注的时间才能完成
那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的。
如果有多个线程同时完成这 6 步操作,也许只需要 1.5s 即可完成响应。
2. 创建异步对象
CompletableFuture 提供了四个静态方法来创建一个异步操作。
java
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)
没有指定Executor的方法会使用ForkJoinPool.commonPool() 作为它的线程池执行异步代码。如果指定线程池,则使用指定的线程池运行。以下所有的方法都类同。
- runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的
- 可以传入自定义的线程池,否则就用默认的线程池
创建线程池对象:
java
public static ThreadPoolExecutor executor = new ThreadPoolExecutor(
5,
200,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100000),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
测试方法:
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main.............start.......");
// 测试1: 创建异步对象:runAsync和supplyAsync方法
// runAsync无返回结果
CompletableFuture<Void> runAsyncFuture = CompletableFuture.runAsync(() -> {
System.out.println("runAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("runAsync当前运行结果:" + i);
}, executor);
// supplyAsync有返回结果
CompletableFuture<Integer> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("supplyAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("supplyAsync当前运行结果:" + i);
return i;
}, executor);
Integer integer = supplyAsyncFuture.get();
System.out.println("supplyAsync获取当前运行结果:" + integer);
System.out.println("main.............end.......");
}
结果:

3.计算结果完成时的回调方法
当CompletableFuture的计算结果完成,或者抛出异常的时候,可以执行特定的Action。主要是下面的方法:
java
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)
- 只能执行回调方法,并返回原结果,不能对之前的结果进行任何处理后返回。
- whenComplete 可以处理正常和异常的计算结果, exceptionally 处理异常情况。
- whenComplete 和 whenCompleteAsync 的区别:
- whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
- whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。
- 方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async 可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
- 可以看到Action的类型是BiConsumer<? super T,? super Throwable>它可以处理正常的计算结果,或者异常情况。
java
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main.............start.......");
// 测试2: 方法成功完成后的回调(无法产生新的返回值)
// 只能执行回调方法,并返回原结果,不能对之前的结果进行任何处理后返回
CompletableFuture<Integer> supplyAsyncFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("supplyAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("supplyAsync当前运行结果:" + i);
return i;
}, executor).whenComplete((result, exception) -> {
// 虽然能得到异常信息,但是没法修改返回数据
System.out.println("异步任务完成了...结果是" + result + ";异常是" + exception);
// 可以感知异常,同时返回默认值
}).exceptionally(throwable -> 10);
Integer integer = supplyAsyncFuture.get();
System.out.println("supplyAsync获取当前运行结果:" + integer);
System.out.println("main.............end.......");
}
结果:

4. handle 方法
handle 是执行任务完成时对结果的处理。 handle 方法和 thenApply 方法处理方式基本一样。不同的是 handle 是在任务完成后再执行,还可以处理异常的任务。thenApply 只可以执行正常的任务,任务出现异常则不执行 thenApply 方法。
java
public <U> CompletionStage<U> handle(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn);
public <U> CompletionStage<U> handleAsync(BiFunction<? super T, Throwable, ? extends U> fn,Execution)
和 complete 一样,可对结果做最后的处理(可处理异常),可改变返回值。
java
// 测试3: 方法成功完成后的回调(可以产生新的返回值)
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, executor).handle((result,thr) -> {
if (result != null) {
return result * 2;
}
if (thr != null) {
System.out.println("异步任务成功完成了...结果是:" + result + "异常是:" + thr);
return 0;
}
return 0;
});
结果

5. 线程串行化
等待上一个操作执行完成后,执行下一个操作:
- thenApply 方法:当一个线程依赖另一个线程时,获取上一个任务返回的结果,并返回当前任务的返回值。
- thenAccept 方法:消费处理结果。接收任务的处理结果,并消费处理,无返回结果。
- thenRun 方法:只要上面的任务执行完成,就开始执行 thenRun,只是处理完任务后,执行 thenRun 的后续操作,不能获取上一步的执行结果。
java
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);
public completionStage<Void> thenAccept (consumer < ? super T > action);
public Completionstage<Void> thenAcceptAsync (Consumer < ? super T > action);
public Completionstage<Void> thenAcceptAsync (consumer < ? super T > action, Executor executor);
public CompletionStage<Void> thenRun (Runnable action);
public Completionstage<Void> thenRunAsync (Runnable action);
public Completionstage<Void> thenRunAsync (Runnable action, Executor executor);
// Function<? super T,? extends U>
// T:上一个任务返回结果的类型
// U:当前任务的返回值类型
带有 Async 默认是异步执行的。同之前。
java
/**
* 4、线程串行化
*/
// 4.1、thenApplyAsync能接收上一步的返回结果,也有返回值
CompletableFuture<String> thenApplyAsync = CompletableFuture.supplyAsync(() -> {
System.out.println("thenApplyAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 5;
System.out.println("thenApplyAsync当前运行结果:" + i);
return i;
}, executor).thenApplyAsync(res -> {
System.out.println("thenApplyAsync任务2启动了。。。。" + res);
return "hello" + res;
}, executor);
String thenApplyAsyncResult = thenApplyAsync.get();
System.out.println("thenApplyAsync返回结果:" + thenApplyAsyncResult);
// 4.2、thenAcceptAsync能接收上一步返回结果,但无返回值
CompletableFuture<Void> thenAcceptAsync = CompletableFuture.supplyAsync(() -> {
System.out.println("thenAcceptAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 5;
System.out.println("thenAcceptAsync当前运行结果:" + i);
return i;
}, executor).thenAcceptAsync(res -> {
System.out.println("thenAcceptAsync任务2启动了。。。。" + res);
}, executor);
// 4.3、thenRun 不能获取得到上一步的执行结果
CompletableFuture<Void> thenRunAsync = CompletableFuture.supplyAsync(() -> {
System.out.println("thenRunAsync当前线程:" + Thread.currentThread().getId());
int i = 10 / 5;
System.out.println("thenRunAsync当前运行结果:" + i);
return i;
}, executor).thenRunAsync(() -> {
System.out.println("thenRunAsync任务2启动了。。。。");
}, executor);
结果

6. 两任务组合-都要完成
两个任务必须都完成后,触发该任务。
- runAfterBoth:两个future不需要获取 future的结果,只需两个 future处理完任务后, 处理该任务。
- thenAcceptBoth:组合两个 future,获取两个 future 任务的返回结果,然后处理任务,没有返回值。
- thenCombine:组合两个 future,获取两个 future 的返回结果,并返回当前任务的返回值
java
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterBothAsync(CompletionStage<?> other,Runnable action,Executor
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action);
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other,BiConsumer<? super T, ? super U> action, Executor executor);
public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn);
public <U,V> CompletableFuture<V> thenCombineAsync(CompletionStage<? extends U> other,BiFunction<? super T,? super U,? extends V> fn,Executor executor);
测试:
java
/**
* 5、两任务组合-都要完成
*/
CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1线程:" + Thread.currentThread().getId());
int i = 10 / 5;
System.out.println("任务1线程结束");
return i;
}, executor);
CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程:" + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("任务2线程结束");
return "hello";
}, executor);
// 5.1、不能得到两个任务的参数,也无返回结果
future01.runAfterBothAsync(future02, () -> {
System.out.println("runAfterBothAsync任务三开始。。。");
}, executor);
// 5.2、能得到两个任务的参数,无返回结果
future01.thenAcceptBothAsync(future02, (f1, f2) -> {
System.out.println("thenAcceptBothAsync任务三开始。。。之前的结果" + f1 + ":" + f2);
}, executor);
// 5.3、能得到两个任务的参数,并返回结果
CompletableFuture<String> thenCombineAsync = future01.thenCombineAsync(future02, (f1, f2) -> {
System.out.println("thenCombineAsync任务三开始。。。之前的结果" + f1 + ":" + f2);
return f1 + ":" + f2 + "->haha";
}, executor);
System.out.println("thenCombineAsync返回结果:" + thenCombineAsync.get());
结果
java
main......start.....
任务2线程:22
任务1线程:21
任务1线程结束
任务2线程结束
runAfterBothAsync任务三开始。。。
thenCombineAsync任务三开始。。。之前的结果2:hello
thenAcceptBothAsync任务三开始。。。之前的结果2:hello
thenCombineAsync返回结果:2:hello->haha
7. 两任务组合-只要有一个任务完成就执行第三个
当两个任务中,任意一个 future 任务完成的时候,执行任务。
- runAfterEither 方法:两个任务有一个执行完成,不需要获取 future 的结果,处理任务,也没有返回值。
- acceptEither 方法:两个任务有一个执行完成,获取它的返回值,处理任务,没有新的返回值。
- applyToEither 方法:两个任务有一个执行完成,获取它的返回值,处理任务并有新的返回值。
- thenCompose 方法:thenCompose 方法允许你对两个 CompletionStage 进行流水线操作,第一个操作完成时,将其结果作为参数传递给第二个操作。
java
public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action);
public CompletableFuture<Void> runAfterEitherAsync(CompletionStage<?> other,Runnable action,Executor executor);
public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other,Consumer<? super T> action);
public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other,Function<? super T, U> fn);
public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn);
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) ;
public <U> CompletableFuture<U> thenComposeAsync(Function<? super T, ? extends CompletionStage<U>> fn) ;
java
/**
* 6、两个任务只要有一个完成,我们就执行任务3
*/
CompletableFuture<Object> future001 = CompletableFuture.supplyAsync(() -> {
System.out.println("future001任务1线程:" + Thread.currentThread().getId());
int i = 10 / 5;
System.out.println("future001任务1线程结束");
return i;
}, executor);
CompletableFuture<Object> future002 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2线程:" + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("future002任务2线程结束");
return "hello";
}, executor);
// 6.1、runAfterEitherAsync 不感知结果,自己也无返回值
future001.runAfterEitherAsync(future002, () -> {
System.out.println("runAfterEitherAsync任务三开始。。。");
}, executor);
// 6.2、acceptEitherAsync 感知结果,自己没有返回值
future001.acceptEitherAsync(future002, (res) -> {
System.out.println("acceptEitherAsync任务三开始。。。" + res);
}, executor);
// 6.3、acceptEitherAsync 感知结果,自己没有返回值
CompletableFuture<String> applyToEitherAsync = future001.applyToEitherAsync(future002, (res) -> {
System.out.println("applyToEitherAsync任务三开始。。。" + res);
return res.toString() + "-> haha";
}, executor);
System.out.println("applyToEitherAsync返回结果:" + applyToEitherAsync.get());
结果
java
main......start.....
任务2线程:22
future001任务1线程:21
future001任务1线程结束
runAfterEitherAsync任务三开始。。。
acceptEitherAsync任务三开始。。。2
applyToEitherAsync任务三开始。。。2
applyToEitherAsync返回结果:2-> haha
future002任务2线程结束
8. 多任务组合
java
// 等待所有任务完成
public static completableFuture<Void> all0f(completableFuture<?>... cfs);
// 只要有一个任务完成
public static completableFuture<Obiect> anyof(completableFuture<?>... cfs);
测试allOf:
java
/**
* 7、多任务组合
*/
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的属性");
return "黑色+256g";
}, executor);
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品的图片信息");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello.jpg";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的介绍");
return "华为";
}, executor);
CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc);
allOf.get(); //等待所有线程执行完
System.out.println("allOf获取结果:" + futureAttr.get() + "=>" + futureImg.get() + "=>" + futureDesc.get());
结果:
java
main......start.....
查询商品的属性
查询商品的介绍
查询商品的图片信息
allOf获取结果:黑色+256g=>hello.jpg=>华为
测试:anyOf
java
/**
* 7、多任务组合
*/
CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的属性");
return "黑色+256g";
}, executor);
CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(3000);
System.out.println("查询商品的图片信息");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "hello.jpg";
}, executor);
CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品的介绍");
return "华为";
}, executor);
// CompletableFuture<Void> allOf = CompletableFuture.allOf(futureAttr, futureImg, futureDesc);
// allOf.get(); //等待所有线程执行完
// System.out.println("allOf获取结果:" + futureAttr.get() + "=>" + futureImg.get() + "=>" + futureDesc.get());
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureAttr, futureImg, futureDesc);
anyOf.get();
System.out.println("anyOf获取结果:" + futureAttr.get() + "=>" + futureImg.get() + "=>" + futureDesc.get());
结果:
java
main......start.....
查询商品的属性
查询商品的介绍
查询商品的图片信息
anyOf获取结果:黑色+256g=>hello.jpg=>华为