SpringBoot整合线程池使用@Async
Posted pcdd
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SpringBoot整合线程池使用@Async相关的知识,希望对你有一定的参考价值。
使用步骤
- 自定义application.yml配置项及其值
- 创建一个线程池配置类
- 创建两个接口OrderService和AsyncOrderService及其实现类
- 创建Controller用于测试
- 观察控制台打印内容的顺序及效果
5.1 使用@Async
5.5 不使用@Async
案例需求:用户下单后,服务端生成订单并保存,然后给用户发短信、邮件通知下单成功
由于短信和邮件发送比较耗时,是秒级别的,所以应采用异步的方式,实现方案有很多,这里使用Spring提供的对ThreadPoolExecutor封装的线程池ThreadPoolTaskExecutor,直接在业务方法上使用注解@Async即可(先用@EnableAsync开启)
线程池ThreadPoolExecutor执行规则如下
1. 自定义application.yml配置项及其值
和创建线程池的参数对应,具体含义见步骤2的成员属性注释,参数根据实际情况自行修改,这里仅作为演示
async:
# 异步订单任务线程池参数
order-service:
core-pool-size: 20
max-pool-size: 100
keep-alive-seconds: 10
queue-capacity: 200
thread-name-prefix: async-order-service-
2. 编写线程池配置类
@Setter
@ConfigurationProperties(prefix = "async.order-service")
@EnableAsync
@Configuration
public class AsyncOrderServiceConfig
/**
* 核心线程数(默认线程数)
*/
private int corePoolSize;
/**
* 最大线程数
*/
private int maxPoolSize;
/**
* 允许线程空闲时间(单位:默认为秒)
*/
private int keepAliveSeconds;
/**
* 缓冲队列大小
*/
private int queueCapacity;
/**
* 线程池名前缀
*/
private String threadNamePrefix;
@Bean
public ThreadPoolTaskExecutor asyncOrderService()
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
threadPoolTaskExecutor.setThreadNamePrefix(threadNamePrefix);
// 线程池对拒绝任务的处理策略
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 完成任务自动关闭 , 默认为false
threadPoolTaskExecutor.setWaitForTasksToCompleteOnShutdown(true);
// 核心线程超时退出,默认为false
threadPoolTaskExecutor.setAllowCoreThreadTimeOut(true);
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
首先通过@EnableAsync开始对异步任务的支持,然后使用@ConfigurationProperties把同类配置信息自动封装成一个实体类。其属性prefix表示application.yml配置文件中配置项的前缀,最后结合Lombok的@Setter保证配置文件的值能够注入到该类对应的属性中
此步其实可省略,因为使用@Async不指定value属性时,SpringBoot默认会创建 SimpleAsyncTaskExecutor线程池来处理异步方法调用
注解@Async定义如下,只有一个value属性(SpringBoot 2.3.7 RELEASE)
3. 创建两个接口OrderService和AsyncOrderService及其实现类
创建订单业务接口
public interface OrderService
/**
* 下订单
*/
void makeOrder();
/**
* 生成订单并保存到数据库
*/
void saveOrder();
创建异步订单业务接口
public interface AsyncOrderService
/**
* 短信服务
*/
void sendSms();
/**
* 邮件服务
*/
void sendEmail();
创建实现类,编写简单逻辑代替业务逻辑
@Slf4j
@Service
public class OrderServiceImpl implements OrderService
@Autowired
private AsyncOrderService asyncOrderService;
@Override
public void makeOrder()
// 发短信
asyncOrderService.sendSms();
// 发邮件
asyncOrderService.sendEmail();
// 保存订单
saveOrder();
@Override
public void saveOrder()
log.info("生成订单并保存...");
@Slf4j
@Service
public class AsyncOrderServiceImpl implements AsyncOrderService
@Async("asyncOrderService")
@Override
public void sendSms()
try
long start = System.currentTimeMillis();
log.info("开始发送短信");
// 模拟耗时3s
TimeUnit.SECONDS.sleep(3);
log.info("短信发送完毕!");
log.info("发送短信耗时: ms", System.currentTimeMillis() - start);
catch (InterruptedException e)
e.printStackTrace();
@Async("asyncOrderService")
@Override
public void sendEmail()
try
long start = System.currentTimeMillis();
log.info("开始发送邮件");
// 模拟耗时2s
TimeUnit.SECONDS.sleep(2);
log.info("邮件发送完毕!");
log.info("发送邮件耗时: ms", System.currentTimeMillis() - start);
catch (InterruptedException e)
e.printStackTrace();
这里使用了@Async注解,它只有一个String类型的value属性,用于指定一个 Bean 的 Name,类型是 Executor 或 TaskExecutor,表示使用这个指定的线程池来执行异步任务,这里指定为步骤2中线程池配置类asyncOrderService
有几点需要注意下,会使@Async失效
● 如果使用SpringBoot框架必须在启动类中增加@EnableAsync注解
● 异步方法不能与被调用的异步方法在同一个类中
● 异步类没有使用@Component注解(或其他同类注解)导致spring无法扫描到异步类
● 类中需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
● 异步方法使用非public或static修饰
4. 创建Controller用于测试
@RestController
public class TestController
@Autowired
private OrderService orderService;
@PostMapping("/makeOrder")
public String makeOrder()
orderService.makeOrder();
return "ok";
5. 观察使用和不用@Async时,控制台打印日志的顺序
使用调式工具调用接口http://localhost:8080/makeOrder,控制台内容如下
使用@Async
不使用@Async
若需对比动态图查看效果,建议刷新页面后即刻查看,效果最佳
使用@Async运行效果
不使用@Async运行效果
从代码逻辑来看,前者是异步执行,后者是同步执行;
从执行效果来看,使用@Async完成速度明显提高
以上是关于SpringBoot整合线程池使用@Async的主要内容,如果未能解决你的问题,请参考以下文章
#yyds干货盘点# springboot配置@Async异步任务的线程池
SpringBoot项目@Async默认线程池导致OOM问题?