异步操作简介
背景分析
当我们项目中的一些非核心业务运行时,影响到用户核心业务的响应时间,导致用户体验下降,我们该如何处理? 由此异步操作方案诞生。
异步应用分析
当我们项目中的一些非核心业务运行时,因其耗时操作(例如用户行为日志的记录),影响到用户核心业务的响应时间,此时可以将这些非核心业务的耗时操作放到新的线程中异步执行。例如:
new Thread(new Runnable() {
@Override
public void run() {
//耗时操作
}
}).start();
对于如上形式的异步实现方式,在并发比较小的时候可以,但是一旦并发量比较大时,反复创建线程和销毁线程会带来很大系统开销,进而影响整体性能。
SpringBoot工程异步实践
概述
SpringBoot 工程中默认支持异步操作,通过异步操作提高核心业务的响应速度。
启动异步
我们可以在SpringBoot工程启动类的上面,添加启动异步操作的注解(@EnableAsync)描述,代码如下:
@EnableAsync
@SpringBootApplication
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class, args);
}
}
定义异步切入点方法
假如此时某个业务方法需要执行异步操作,可以使用@Async注解对方法进行描述,例如写日志的业务,关键代码如下:
@Async
public void saveLog(SysLog entity){
sysLogDao.insertLog(entity);
}
其中,@Async注解描述的方法,在Spring中会认为这是一个异步切入点方法, 在这个切入点方法执行时,底层会通过通知方法获取线程池中的线程,通过池中的线程调用切入点方法(底层默认池类型为ThreadPoolExecutor类型)
假如异步方法有返回值,可以采用AsyncResult对返回值进行封装,例如:
@Async
public Future<Integer> saveLog(SysLog entity){
int result=sysLogDao.insertLog(entity);
return new new AsyncResult<Integer>(result);
}
虽然Future可以用于描述一个异步计算的结果,但是这个结果值的获取还是需要阻塞获取。如果阻塞获取其实没意义了,本来想用异步就是为了不阻塞,所以一般建议阻塞方法不写具体返回值。
自定义线程池的配置
SpringBoot工程在启动时,会默认配置一个线程池,当默认的线程池配置,不满足我们实际项目需求时,我们可以对线程池进行自定义的配置,SpringBoot配置文件application.properties(或者application.yml)中的关键配置如下:
spring.task.execution.pool.core-size=8
spring.task.execution.pool.max-size=256
spring.task.execution.pool.keep-alive=60000
spring.task.execution.pool.queue-capacity=512
spring.task.execution.thread-name-prefix=async-service-task-
其中:
- core-size :核心线程数,当池中线程数没达到core-size的值时,每接收一个新的任务都会创建一个新线程,然后存储到池。假如池中线程数已经达到core-size设置的值,再接收新的任务时,要检测是否有空闲的核心线程,假如有,则使用空闲的核心线程执行新的任务。
- queue-capacity:队列容量,假如核心线程数已达到core-size设置的值,并且所有的核心线程都在忙,再来新的任务,会将任务存储到任务队列。
- max-size: 最大线程数,当任务队列已满,核心线程也都在忙,再来新的任务则会创建新的线程,但所有线程数不能超过max-size设置的值,否则可能会出现异常(拒绝执行)
- keep-alive:线程空闲时间,假如池中的线程数多余core-size设置的值,此时又没有新的任务,则一旦空闲线程空闲时间超过keep-alive设置的时间值,则会被释放。
- thread-name-prefix:线程名的前缀,项目中设置线程名的目的主要是为了对线程进行识别,一旦出现线程问题,可以更好的定位问题。
总结(Summary)
本小节重点讲解了我们的项目中为什么需要异步设计,如何进行异步设计,以及SpringBoot工程中如何进行异步实现。
本文由 liyunfei 创作,采用 知识共享署名4.0
国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为: Jun 29,2022