当我们有如下场景:
以上要么去数据库中查询,要么就远程调用查询,所花费的时间都不一样,那么我们很容易想到使用多线程来解决该问题,但是如果有各种麻烦的顺序(比如5要在1、2后执行,6要在2、3后执行),我们这时使用多线程就会比较复杂。
那么现在有个类CompletableFuture 来封装了这种复杂性:
CompletableFuture
对于CompletableFuture类的每一个方法,都有提供线程池和不提供线程池两种方法,如果不提供线程池就会使用它自定义的线程池。我们这里使用我们提供的线程池。
runAsync() 和 supplyAsync()
CompletableFuture有几个基本的方法: runAsync
,supplyAsync
,看下面的例子就懂了区别:
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<Void> async = CompletableFuture.runAsync(() -> {
System.out.println("当前正在执行");
}, executorService);
CompletableFuture<String> async1 = CompletableFuture.supplyAsync(() -> {
return "返回值";
}, executorService);
System.out.println(async1.get());
可以发现,runAsync()
是没有返回值的,supplyAsync()
是有返回值的,通过返回的CompletableFuture类调用get()
方法得到具体的返回值
线程完成后的处理
主要的方法有handle()
和 exceptionally()
, 第一个方法可以拿到返回值和异常,第二个方法只能拿到异常。
CompletableFuture.supplyAsync(()->{
return "hello";
},executorService).handle((t,u)->{
return "结果是"+t+","+"异常有:"+u ;
})
.exceptionally(e->{
System.out.println();
return "异常处理后的返回值";
});
串行化
thenRunAsync()
该方法只能串行化的执行,第二个线程不能接收到第一个线程的任何信息
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.supplyAsync(() -> {
return "返回值";
}, executorService).thenRunAsync(() -> {
System.out.println("");
});
thenAcceptAsync()
该方法可以拿到第一个线程的返回值:
CompletableFuture.supplyAsync(()->{
return "hello";
}).thenAcceptAsync(r->{
System.out.println("前一个线程的返回值是"+r);
},executorService);
thenApplyAsync
该方法不仅可以拿到前一个线程的返回值,也可以自己返回值:
CompletableFuture.supplyAsync(()->{
return "hello";
}).thenApplyAsync(r->{
return "new"+r;
},executorService);
带顺序的异步处理:
现在就来解决我们最开始提出的问题:
ExecutorService executorService = Executors.newFixedThreadPool(10);
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品属性信息");
return "iphone";
}, executorService);
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品图片");
return "http://aaa.jpg";
}, executorService);
CompletableFuture<String> future3 = CompletableFuture.supplyAsync(() -> {
System.out.println("查询商品介绍");
return "Iphone 13";
}, executorService);
如上,现在有三个任务是异步执行的,那么我们需要第5个任务是1和2之后执行,6要在2、3后执行,那么就使用allof()
方法
CompletableFuture<String> future5 = CompletableFuture.allOf(future1, future2).thenApplyAsync((r) -> {
return "第五个任务执行完毕";
}, executorService);
System.out.println(future5.get());
CompletableFuture<String> future6 = CompletableFuture.allOf(future2, future3).thenApplyAsync((r) -> {
return "第六个任务执行完毕";
}, executorService);
System.out.println(future6.get());
当我们执行future5.get()和 future6.get()的方法时,future5会阻塞等待1和2 的完成,future6会阻塞等待2和3的完成,
除了allof()
方法外,还有一个 anyof()
方法,就是等待其中之一的线程执行完毕之后就执行后面的线程