业务场景:

查询详情页的逻辑比较多,有些数据还需要远程调用,必然要花费更多的时间。

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");
}

CompletableFuture异步任务编排_Thread

 

2、runAsync

没有返回结果的方法调用:

CompletableFuture异步任务编排_java_02

 

3、supplyAsync

有返回结果的方法调用:无论是否get操作,使用了改操作,就是阻塞式等待。

CompletableFuture异步任务编排_java_03

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());

 返回结果:

CompletableFuture异步任务编排_Thread_04

 

可以理解为多线程同步调用。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");

 执行结果:

CompletableFuture异步任务编排_异步_05

如果,i=10/0的执行结果如下:

2、exceptionally

CompletableFuture异步任务编排_线程池_06

总结:

使用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;
});

 执行结果:

CompletableFuture异步任务编排_java_07

 

4、线程串行化方法

CompletableFuture异步任务编排_线程池_08

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 肯定是抛出异常了,但是咱们抛出了异常,所以程序中断;

CompletableFuture异步任务编排_Thread_09

 如果修改异常代码,i=10/2;

CompletableFuture异步任务编排_Thread_10

如果使用了thenRun,则是用该线程继续执行任务。

CompletableFuture异步任务编排_异步_11

 

thenAcceptAsync:

CompletableFuture异步任务编排_线程池_12

 

 得到上一步的返回结果,但是新任务结果不返回。

 

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);
});

 执行结果:

CompletableFuture异步任务编排_返回结果_13

thenApplyAsync:

CompletableFuture异步任务编排_异步_14

 

得到上一步的返回结果,并且返回新任务的结果。

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");

 

 执行结果:

CompletableFuture异步任务编排_异步_15

 

两个任务组合,都要完成

两个任务都完成以后,触发一个事件

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的返回结果,新开一个独立线程运行,不是在线程池中");
});

 

CompletableFuture异步任务编排_Thread_16

future01.thenAcceptBothAsync(future02, (res1, res2) -> {
System.out.println("thenAcceptBothAsync:" + "会获取到线程1和线程2的返回结果,res1=" + res1 + ",res2=" + res2 + ",但是新任务不会返回!");
}, pool);

 

 

CompletableFuture异步任务编排_异步_17

 

CompletableFuture<Object> future = future01.thenCombineAsync(future02, (res1, res2) -> {
return res1+"----"+res2;
}, pool);
System.out.println(future.get().toString());
System.out.println("main ... end");

 执行结果:

CompletableFuture异步任务编排_java_18

 

两个任务组合,一个完成

当两个任务中,任意一个future任务完成的时候,执行该任务。

applyToEither:两个任务有一个任务执行完成,获取它的返回值,处理任务并有新的返回值。

acceptEither:两个任务有一个任务执行完成,获取它的返回值,处理任务,没有返回值。

runAfterEither:两个任务有一个任务执行完成,不需要获取它的返回值,处理任务,并且没有返回值。

 

多任务组合

allOf:等待所有任务完成

anyOf:只要有一个任务完成

CompletableFuture<Void> allOf = CompletableFuture.allOf(future01, future02, future03);
allOf.get();
System.out.println("main ... end");

 

CompletableFuture异步任务编排_Thread_19

执行结果:

CompletableFuture异步任务编排_Thread_20

如果不加线程池,主线程结束,其余线程也会结束掉。其余线程就不打印东西了。所以要想清楚的看到结果,将线程执行放入到线程池中。