业务场景:
查询详情页的逻辑比较多,有些数据还需要远程调用,必然要花费更多的时间。
1、获取SKU的基本信息 0.5s
2、获取SKU的图片信息 0.5s
3、获取SKU的促销信息 1s
4、获取SPU的所有销售属性 1s
5、获取SPU的详情 1.5s
假如商品详情页的每个查询,如果如上标注的时间才能完成,那么用户需要4.5秒的时间,才能够看到商品详情页面的内容,很显然是不能够接受的。
如果有多个线程同时完成这6步操作,也许仅仅1.5秒就能够完成。
4 5 需要1的返回结果。
completableFuture简单调用
1、简单调用
//测试异步任务
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main .... start");
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
}, pool);
System.out.println("main ... end");
}
2、runAsync
没有返回结果的方法调用:
3、supplyAsync
有返回结果的方法调用:无论是否get操作,使用了改操作,就是阻塞式等待。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool);
System.out.println(future.get());
返回结果:
可以理解为多线程同步调用。get方法为阻塞式等待。
完成时的回调方法
1、whenComplete
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).whenComplete((result,exception)->{
System.out.println("继续上一个线程的执行结果,用同一个线程继续执行");
System.out.println("result="+result);
System.out.println("exception="+exception);
}).exceptionally(excep->{
return 10; //遭遇到异常的返回结果
});
System.out.println(future.get());
System.out.println("main ... end");
执行结果:
如果,i=10/0的执行结果如下:
2、exceptionally
总结:
使用whenComplete的回调方法,参数一:返回结果;参数二:异常。但是该方法无法修改返回结果。是执行当前任务的线程继续执行回调方法的任务。
whenCompleteAsync:是执行把whenCompleteAsync这个任务继续提交给线程池来进行执行。
方法不以Async结尾,意味着Action使用相同的线程执行,而Async可能会使用其他线程执行。(如果是使用相同的线程池,也可能会被同一个线程选中执行)
使用exceptionally,如果遭遇到异常,可以修改返回结果的值。
3、handle方法完成后的处理
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, pool).handle((result,exception)->{
if(result!=null){
return result;
}
if(exception!=null){
return 0;
}
return 0;
});
执行结果:
4、线程串行化方法
thenRunAsync:
不得到上一步的返回结果,直接异步执行任务。
CompletableFuture<Void> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, pool).thenRunAsync(()->{
System.out.println("哈哈");
},pool);
注意:此时,i=10/0 肯定是抛出异常了,但是咱们抛出了异常,所以程序中断;
如果修改异常代码,i=10/2;
如果使用了thenRun,则是用该线程继续执行任务。
thenAcceptAsync:
得到上一步的返回结果,但是新任务结果不返回。
CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).thenAccept(res->{
System.out.println("res="+res);
});
执行结果:
thenApplyAsync:
得到上一步的返回结果,并且返回新任务的结果。
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, pool).thenApplyAsync(res -> {
System.out.println("res=" + res);
return 8;
}, pool);
System.out.println("get===="+future.get());
System.out.println("main ... end");
执行结果:
两个任务组合,都要完成
两个任务都完成以后,触发一个事件
thenCombine:
组合两个future,获取两个future的返回结果,并返回当前任务的返回值;
thenAcceptBoth:
组合两个future,获取两个future的返回结果,然后处理任务,没有返回值;
runAfterBoth:组合两个future,不需要获取future的返回结果,只需要两个future处理任务完成后,处理该任务。
CompletableFuture<Integer> future01 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程1的ID:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("线程1结束:返回结果为" + i);
return i;
}, pool);
CompletableFuture<String> future02 = CompletableFuture.supplyAsync(() -> {
System.out.println("线程2的ID:" + Thread.currentThread().getId());
return "线程2结束";
}, pool);
//Async加上就是异步,到最后执行;不加就是约等于同步
future01.runAfterBothAsync(future02,()->{
System.out.println("runAfterBoth:"+"不要线程1和线程2的返回结果,新开一个独立线程运行,不是在线程池中");
});
future01.thenAcceptBothAsync(future02, (res1, res2) -> {
System.out.println("thenAcceptBothAsync:" + "会获取到线程1和线程2的返回结果,res1=" + res1 + ",res2=" + res2 + ",但是新任务不会返回!");
}, pool);
CompletableFuture<Object> future = future01.thenCombineAsync(future02, (res1, res2) -> {
return res1+"----"+res2;
}, pool);
System.out.println(future.get().toString());
System.out.println("main ... end");
执行结果:
两个任务组合,一个完成
当两个任务中,任意一个future任务完成的时候,执行该任务。
applyToEither:两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。
acceptEither:两个任务有一个任务执行完成,获取它的返回值,处理任务,没有返回值。
runAfterEither:两个任务有一个任务执行完成,不需要获取它的返回值,处理任务,并且没有返回值。
多任务组合
allOf:等待所有任务完成
anyOf:只要有一个任务完成
CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
allOf.get();
System.out.println("main ... end");
执行结果:
如果不加线程池,主线程结束,其余线程也会结束掉。其余线程就不打印东西了。所以要想清楚的看到结果,将线程执行放入到线程池中。