异步调用
单线程情况下,接口响应给客户端时间变慢 ,异步线程会单独开启一个线程,提高响应效率。
创建类
@RequestMapping("/add")
public String add(){
log.info(">01<");
sms();
log.info(">04<");
return "用户注册成功";
}
public String sms(){
log.info(">02<");
try{
log.info(">正在发送信息。。<");
Thread.sleep(3000);
}catch (Exception e){
}
log.info(">03<");
return "短信发送完成";
}
发现加载网页变慢
可以看到单线程环境下的执行顺序1,2,3,4。
开启一个新线程发送短信。
发现执行顺序发生变化1,4,2,3
使用@Async实现异步调用
使用异步注解
启动加上@EnableAsync ,需要执行异步方法上加入@Async
异步应用场景
@Async实际就是多线程封装的
异步线程执行方法有可能会非常消耗cpu的资源,所以大的项目建议使用Mq异步实现。
@Async失效问题
使用@Async注解。
发现并没作用,程序又成单线程了。
注意:如果异步注解写当前自己类,有可能aop会失效,无法拦截注解,最终导致异步注解失效,需要经过代理类调用接口;所以需要将异步的代码单独抽取成一个类调用接口。
新建接口类
@Component
@Slf4j
public class Asyns {
@Async
public String sms() {
log.info(">02<");
try {
log.info(">正在发送信息。。<");
Thread.sleep(3000);
} catch (Exception e) {
}
log.info(">03<");
return "短信发送完成";
}
可以看到成果。
使用@Async整合线程池
创建线程池
api配置
下面配置最多创建3个线程,然后不停复用。
@Configuration
@EnableAsync
public class ThreadPoolConfig {
/**
* 每秒需要多少个线程处理?
* tasks/(1/taskcost)
*/
private int corePoolSize = 3;
/**
* 线程池维护线程的最大数量
* (max(tasks)- queueCapacity)/(1/taskcost)
*/
private int maxPoolSize = 3;
/**
* 缓存队列
* (coreSizePool/taskcost)*responsetime
*/
private int queueCapacity = 10;
/**
* 允许的空闲时间
* 默认为60
*/
private int keepAlive = 100;
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(corePoolSize);
// 设置最大线程数
executor.setMaxPoolSize(maxPoolSize);
// 设置队列容量
executor.setQueueCapacity(queueCapacity);
// 设置允许的空闲时间(秒)
//executor.setKeepAliveSeconds(keepAlive);
// 设置默认线程名称
executor.setThreadNamePrefix("thread-");
// 设置拒绝策略rejection-policy:当pool已经达到max size的时候,如何处理新任务
// CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
结果