一、问题背景
在查询商品详情信息时比较复杂,其中可能还涉及到远程调用,这会消耗很多的时间,如:
// 获取商品基本信息 0.5s
// 获取商品图片信息 1s
// 获取商品的销售属性 1s
// 获取商品的规格参数 1s
// ...
那么这个查询用户需要3.5秒后才能看到页面数据,如果有多个线程同时完成这4个步骤,也许只需要1秒就能看到数据
而在Java8后提供了一个CompletableFuture来帮我们实现这个功能,CompletableFuture,提供了非常强大的 Future 的扩展功能,可以帮助我们简化异步编程的复杂性,提供了函数式编程的能力,可以通过回调的方式处理计算结果,并且提供了转换和组合 CompletableFuture 的方法。 CompletableFuture 类实现了 Future 接口,所以你还是可以像以前一样通过get方法阻塞或者轮询的方式获得结果
创建异步对象
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都是没有返回结果的,supplyAsync都是可以获取返回结果的
可以传入自定义的线程池,否则就用默认的线程池;
线程串行化
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)
Function<? super T,? extends U> T:上一个任务返回结果的类型 U:当前任务的返回值类型
多任务组合
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)
allOf:所有任务都完成,anyOf:任何一个任务执行完成
下面就通过具体代码来演示如何使用:
无返回值runAsync
public class Test {
/** 自定义一个线程池 */
private static final ThreadPoolExecutor SERVICE = new ThreadPoolExecutor(
10, 20,60, TimeUnit.SECONDS,
new LinkedBlockingDeque<>(60));
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 无返回值
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println(Thread.currentThread().getName() + "---->无返回值异步开始");
}, SERVICE);
}
}
获取返回结果supplyAsync
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 有返回值
CompletableFuture<Integer> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("---->返回值异步开始");
int i = 10 / 0;
return 1;
}, SERVICE).whenComplete((res, exeption) -> {
// 异步完成后的回调
System.out.println("结果:" + res + "\t异常:" + exeption);
}).exceptionally(exeption -> {
// 可以进一步处理异常,改变返回值
System.out.println("异常:" + exeption);
return 20;
});
}
使用handle接收
public static void main(String[] args) throws ExecutionException, InterruptedException {
CompletableFuture<Integer> uCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("---->返回值异步开始");
int i = 10 / 0;
return 1;
}, SERVICE).handle((res, exeption) -> {
if (exeption != null) {
System.out.println("异常原因:" + exeption);
return -1;
}else {
System.out.println("结果为:" + res);
return res;
}
});
}
线程串行化方法
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
* 不能接收上一步的结果,也没有返回值
* .thenRunAsync(() -> {
* System.out.println("任务二启动了....");
* }, SERVICE)
*
* 能接收上一步的结果有返回值
* .thenApplyAsync((res) -> {
* System.out.println("上一步的结果:" + res);
* return "1";
* }, SERVICE);
*
* 能接收上一步的结果但没有返回值
* .thenAcceptAsync((res) -> {
* System.out.println("上一步的结果为:" + res);
* }, SERVICE)
*/
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
System.out.println("---->返回值异步开始");
// int i = 10 / 0;
return 1;
}, SERVICE).thenApplyAsync((res) -> {
System.out.println("上一步的结果:" + res);
return "1";
}, SERVICE);
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
// 第一个任务
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("---->任务1异步开始...");
return 1;
}, SERVICE);
// 第二个任务
CompletableFuture<Integer> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("---->任务2异步开始....");
try {
Thread.sleep(2000);
System.out.println("任务二结束...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return 2;
}, SERVICE);
// 不能接收前两个的结果,也无返回值
future01.runAfterBothAsync(future02, () -> System.out.println("任务三开始"), SERVICE);
// 能接收前两个的结果,无返回值
future01.thenAcceptBothAsync(future02, (res1, res2) -> {
System.out.println("任务一的结果为:" + res1);
System.out.println("任务二的结果为:" + res2);
}, SERVICE);
// 能接收前两个的结果,有返回值
CompletableFuture<String> future03 = future01.thenCombineAsync(future02, (res1, res2) -> {
return res1 + res2 + "";
}, SERVICE);
/*
两个任务只要有一个完成,就执行下一步
*/
// 不接收上一步结果,也无返回值
future01.runAfterEitherAsync(future02, () -> System.out.println("任务三开始"), SERVICE);
// 接收上一步结果,无返回值,(任务一和任务二的返回值结果应该同一类型)
future01.acceptEitherAsync(future02, (res1) -> {
}, SERVICE);
// 接收上一步的结果,有返回值
future01.applyToEitherAsync(future01, (res)-> {
return "q";
}, SERVICE);
}
任务组合
public static void main(String[] args) throws ExecutionException, InterruptedException {
/*
多任务组合
allOf:所有都完成
anyOf:只要一个完成
*/
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("---->任务1异步开始...");
return 1;
}, SERVICE);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("---->任务2异步开始....");
try {
Thread.sleep(2000);
System.out.println("任务二结束...");
} catch (InterruptedException e) {
e.printStackTrace();
}
return "2";
}, SERVICE);
CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02);
// 获取执行结果,会阻塞
allOf.get();
System.out.println("1:" + future01.get() + "\t2:" + future02.get());
CompletableFuture<Object> anyOf = CompletableFuture.anyOf(future01, future02);
// 返回的是先执行完返回的数据
Object o = anyOf.get();
System.out.println("main--->end...");
}