1. 概念理解:
多线程和异步调用之前一直不理解有什么区别,发现,这两个是一件事情的不同角度,多线程是方法,异步是目的
在springboot 可以通过注解@Async 搞定。
线程池:线程池引入的目的是为了解决:多次使用线程意味着,我们需要多次创建并销毁线程。而创建并销毁线程的过程势必会消耗内存;线程池的好处,就是可以方便的管理线程,也可以减少内存的消耗。
在springboot 提供ThreadPoolTaskExecutor 线程池
无返回值的任务使用public void execute(Runnable command) 方法提交:
子线程可能在主线程结束之后结束
有返回值的任务使用public <T> Future<T> submit(Callable) 方法提交:因为提交任务后有个取数据的过程,在从
Future取数据的过程中,Callable自带的阻塞机制,这个机制保证主线程一定在子线程结束之后结束。反之如果没有取数据,子线程可能会在主线程结束之后才结束。
Future:可用来接受多线程结果值
其中有5个方法:比较常用的是 get() 和isDone()
get()方法可以当任务结束后返回一个结果,如果调用时,工作还没有结束,则会阻塞线程,直到任务执行完毕
get(long timeout,TimeUnit unit)做多等待timeout的时间就会返回结果
cancel(boolean mayInterruptIfRunning)方法可以用来停止一个任务,如果任务可以停止(通过mayInterruptIfRunning来进行判断),则可以返回true,如果任务已经完成或者已经停止,或者这个任务无法停止,则会返回false.
isDone()方法判断当前方法是否完成
isCancel()方法判断当前方法是否取消
2. 实现方法
(1)配置线程池
@Configuration
public class GlobalConfigA {
@Bean("taskExecutor")
public ThreadPoolTaskExecutor defaultThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程数目
executor.setCorePoolSize(16);
//指定最大线程数
executor.setMaxPoolSize(64);
//队列中最大的数目
executor.setQueueCapacity(16);
//线程名称前缀
executor.setThreadNamePrefix("defaultThreadPool_");
//rejection-policy:当pool已经达到max size的时候,如何处理新任务
//CALLER_RUNS:不在新线程中执行任务,而是由调用者所在的线程来执行
//对拒绝task的处理策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//线程空闲后的最大存活时间
executor.setKeepAliveSeconds(60);
//加载
executor.initialize();
return executor;
}
}
(2)实现异步,多线程(@Async)
@Component
public class AsyncTask {
@Async("taskExecutor")
public void tesTask(int i){
System.out.println(Thread.currentThread().getName()+"-----"+i);
}
@Async("taskExecutor")
public CompletableFuture stringTask(String str){
return CompletableFuture.completedFuture(str);
}
}
(2)实现方式2
executor.submit
//通过注解引入配置
@Resource(name = "taskExecutor")
private ThreadPoolTaskExecutor executor;
//使用Future方式执行多任务
//生成一个集合
List<Future> futures = new ArrayList<>();
//获取后台全部有效运营人员的集合
List<AdminUserMsgResponse> adminUserDOList = adminManagerService.GetUserToSentMsg(null);
for (AdminUserMsgResponse response : adminUserDOList) {
//并发处理
if (response.getMobile() != null) {
Future<?> future = executor.submit(() -> {
//发送短信
mobileMessageFacade.sendCustomerMessage(response.getMobile(), msgConfigById.getContent());
});
futures.add(future);
}
}
//查询任务执行的结果
for (Future<?> future : futureList) {
while (true) {//CPU高速轮询:每个future都并发轮循,判断完成状态然后获取结果,这一行,是本实现方案的精髓所在。即有10个future在高速轮询,完成一个future的获取结果,就关闭一个轮询
if (future.isDone()&& !future.isCancelled()) {//获取future成功完成状态,如果想要限制每个任务的超时时间,取消本行的状态判断+future.get(1000*1, TimeUnit.MILLISECONDS)+catch超时异常使用即可。
Integer i = future.get();//获取结果
System.out.println("任务i="+i+"获取完成!"+new Date());
list.add(i);
break;//当前future获取结果完毕,跳出while
} else {
Thread.sleep(1);//每次轮询休息1毫秒(CPU纳秒级),避免CPU高速轮循耗空CPU---》新手别忘记这个
}
}
}