1.业务场景
查询商品详情页的逻辑比较复杂,有些数据还需要远程调用,必然需要花费更多的时间
假如商品详情页的每个查询,需要如下标注的时间才能完成
那么,用户需要 5.5s 后才能看到商品详情页的内容。很显然是不能接受的。
如果有多个线程同时完成这 6 步操作,也许只需要 1.5s 即可完成响应
2.什么是CompletableFuture
在jdk8中CompletableFuture属于Future 接口的实现类,可以获取线程的执行结果(idea中ctrl+alt+shift+u可以查看继承图),类似于Node.js中的Promise
3.创建异步对象
CompletableFuture 提供了4个静态方法来创建一个异步操作
- runXxxx 都是没有返回结果的,supplyXxx 都是可以获取返回结果的
- 可以传入自定义的线程池,否则就用默认的线程池
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) ;
代码示例
package com.atguigu.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 异步编排CompletableFuture(创建异步对象)
* @author zfh
* @email hst1406959716@163.com
* @date 2022-01-04 09:40:46
*/
public class CompletableFutureDemo {
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,200,10,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(10000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main......start.....");
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
},threadPoolExecutor);
System.out.println("main......end......." );
}
}
package com.atguigu.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 异步编排CompletableFuture(创建异步对象)
* @author zfh
* @email hst1406959716@163.com
* @date 2022-01-04 09:40:46
*/
public class CompletableFutureDemo {
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,200,10,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(10000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main......start.....");
CompletableFuture.supplyAsync(()->{
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
},threadPoolExecutor);
System.out.println("main......end......." );
}
}
可以获取返回结果
package com.atguigu.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 异步编排CompletableFuture(创建异步对象)
* @author zfh
* @email hst1406959716@163.com
* @date 2022-01-04 09:40:46
*/
public class CompletableFutureDemo {
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,200,10,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(10000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main......start.....");
// CompletableFuture.supplyAsync(()->{
// System.out.println("当前线程:" + Thread.currentThread().getId());
// int i = 10 / 2;
// System.out.println("运行结果:" + i);
// return i;
// },threadPoolExecutor);
//也可获取返回值
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, threadPoolExecutor);
Integer integer = integerCompletableFuture.get();
System.out.println("main......end......." + integer);
}
}
4.计算完成时回调方法
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);
- a.whenComplete 可以处理正常和异常的计算结果,exceptionally 处理异常情况
- b.whenComplete 和 whenCompleteAsync 的区别:
whenComplete:是执行当前任务的线程执行继续执行 whenComplete 的任务。
whenCompleteAsync:是执行把 whenCompleteAsync 这个任务继续提交给线程池来进行执行。 - c.方法不以 Async 结尾,意味着 Action 使用相同的线程执行,而 Async可能会使用其他线程执行(如果是使用相同的线程池,也可能会被同一个线程选中执行)
package com.atguigu.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 异步编排CompletableFuture(计算完成时回调方法)
* @author zfh
* @email hst1406959716@163.com
* @date 2022-01-04 09:48:36
*/
public class CompletableFutureDemo2 {
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,100,10,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(1000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main......start.....");
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 2;
System.out.println("运行结果:" + i);
return i;
}, threadPoolExecutor).whenComplete((res,exceptiom)->{
//能感知异常,但不能修改返回数据
System.out.println("异步任务成功完成啦....结果是:" + res + ";异常是:" + exceptiom);
});
System.out.println("main......end......." );
}
}
改成10/0
使用exceptionally
package com.atguigu.gulimall.search.thread;
import java.util.concurrent.*;
/**
* 异步编排CompletableFuture(计算完成时回调方法)
* @author zfh
* @email hst1406959716@163.com
* @date 2022-01-04 09:48:36
*/
public class CompletableFutureDemo2 {
public static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
5,100,10,
TimeUnit.SECONDS,new LinkedBlockingDeque<>(1000),
Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());
public static void main(String[] args) throws ExecutionException, InterruptedException {
System.out.println("main......start.....");
/**
* 方法完成后的感知
*/
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("当前线程:" + Thread.currentThread().getId());
int i = 10 / 0;
System.out.println("运行结果:" + i);
return i;
}, threadPoolExecutor).whenComplete((res,exceptiom)->{
//能感知异常,但不能修改返回数据
System.out.println("异步任务成功完成啦....结果是:" + res + ";异常是:" + exceptiom);
}).exceptionally(throwable -> {
//能感知异常,能修改返回数据(作为默认值)
return 10;
});
Integer integer = integerCompletableFuture.get();
System.out.println("main......end......." + integer);
}
}