07-SpringBoot工程中异步(Async)操作实践

异步操作简介

背景分析

当我们项目中的一些非核心业务运行时,影响到用户核心业务的响应时间,导致用户体验下降,我们该如何处理? 由此异步操作方案诞生。

异步应用分析

当我们项目中的一些非核心业务运行时,因其耗时操作(例如用户行为日志的记录),影响到用户核心业务的响应时间,此时可以将这些非核心业务的耗时操作放到新的线程中异步执行。例如:

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工程中如何进行异步实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

青木编码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值