SpringBoot使用异步线程池实现生产环境批量数据推送
前言
SpringBoot使用异步线程池:
1、编写线程池配置类,自定义一个线程池;
2、定义一个异步服务;
3、使用@Async注解指向定义的线程池;
这里以我工作中使用过的一个案例来做描述,我所在公司是医疗行业,敏感数据需要上报到某监管平台,所以有一个定时任务在流量较小时(一般是凌晨后)执行上报行为。但特殊时期会存在一定要在工作时间大批量上报数据的情况,且要求短时间内就要完成,此时就考虑写一个专门的异步上报接口手动执行,利用线程池上报,极大提高了速度。
编写线程池配置类
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor; /**
* 类名称:ExecutorConfig
* ********************************
* <p>
* 类描述:线程池配置
*
* @author guoj
* @date 2021-09-07 09:00
*/
@Configuration
@EnableAsync
@Slf4j
public class ExecutorConfig {
/**
* 定义数据上报线程池
* @return
*/
@Bean("dataCollectionExecutor")
public Executor dataCollectionExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 核心线程数量:当前机器的核心数
executor.setCorePoolSize(
Runtime.getRuntime().availableProcessors()); // 最大线程数
executor.setMaxPoolSize(
Runtime.getRuntime().availableProcessors() * 2); // 队列大小
executor.setQueueCapacity(Integer.MAX_VALUE); // 线程池中的线程名前缀
executor.setThreadNamePrefix("sjsb-"); // 拒绝策略:直接拒绝
executor.setRejectedExecutionHandler(
new ThreadPoolExecutor.AbortPolicy()); // 执行初始化
executor.initialize(); return executor;
} }PS:
1)、需要注意,这里一定要自己定义ThreadPoolTaskExecutor线程池,否则springboot的异步注解会执行默认线程池,存在线程阻塞导致CPU飙高及内存溢出的风险。这一点可以参考阿里开发手册,线程池定义这块明确提到了这一点;
2)、在@Bean注解中定义线程池名称,后面异步注解会用到。
编写异步服务
/**
* 异步方法的服务, 不影响主程序运行。
*/
@Service
public class AsyncService { private final Logger log = LoggerFactory.getLogger(AsyncService.class); /**
* 发送短信
*/
@Async("sendMsgExecutor")
public void sendMsg(String access_token, Consult item, Map<String, String> configMap) {
// 此处编写发送短信业务
// 1、buildConsultData();
// 2、sendMsg();
} /**
* 发送微信订阅消息
*/
@Async
public void sendSubscribeMsg(String access_token, Consult item, Map<String, String> configMap) {
// 此处编写发送微信订阅消息业务
// 1、buildConsultData();
// 2、sendSubscribeMsg();
} /**
* 数据并上报
*/
@Async("dataCollectionExecutor")
public void buildAndPostData(String access_token, Consult item, Map<String, String> configMap) {
// 此处编写上报业务,如拼接数据,然后执行上报。
// 1、buildConsultData();
// 2、postData();
}
}
异步批量上报数据
@Autowired
private AsyncService asyncService; /**
* 手动上报问诊记录,线程池方式。
*/
public void manualUploadConsultRecordsAsync(String channel, Date startTime, Date endTime) { // 查询指定时间内的问诊记录
List<Consult> consultList = consultService
.findPaidListByChannelAndTime(channel, startTime, endTime, configMap.get("serviceId")); if (!CollectionUtils.isEmpty(consultList)) { log.debug("[SendWZDataService][manualUploadConsultRecordsAsync]>>>> 手动上报问诊记录, 一共[{}]条", consultList.size()); consultList.forEach((item) -> {
try {
// 异步调用,使用线程池。
asyncService.buildAndPostData(access_token, item, configMap);
} catch (Exception ex) {
log.error("[SendWZDataService][manualUploadConsultRecordsAsync]>>>> 手动上报问诊记录发生异常: ", ex);
}
}); }
}
总结
以上方式已经在生产环境运行,在工作时间内执行过很多次,一次数万条记录基本是几分钟内就全部上报完毕,而正常循环遍历时一次大概需要半个小时左右。 线程池的使用方式往往来源于业务场景,如果类似的业务不存在紧急处理的情况,大体还是以任务调度执行为主,因为更安全。如果存在紧急处理的情况,那么使用SpringBoot+线程池的方式不仅能节省非常多的时间,且不占用主线程的执行空间。 喜欢就点个关注吧~~
SpringBoot使用异步线程池实现生产环境批量数据推送的更多相关文章
- Springboot的异步线程池
1:定义线程池 @EnableAsync @Configuration class TaskPoolConfig { @Bean("taskExecutor") public Ex ...
- springboot+@async异步线程池的配置及应用
示例: 1. 配置 @EnableAsync @Configuration public class TaskExecutorConfiguration { @Autowired private Ta ...
- spring boot:使用async异步线程池发送注册邮件(spring boot 2.3.1)
一,为什么要使用async异步线程池? 1,在生产环境中,有一些需要延时处理的业务场景: 例如:发送电子邮件, 给手机发短信验证码 大数据量的查询统计 远程抓取数据等 这些场景占用时间较长,而用户又没 ...
- springBoot服务整合线程池ThreadPoolTaskExecutor与@Async详解使用
ThreadPoolExecutor:=======这个是java自己实现的线程池执行类,基本上创建线程池都是通过这个类进行的创建.ThreadPoolTaskExecutor:========这个是 ...
- 使用C++11 开发一个半同步半异步线程池
摘自:<深入应用C++11>第九章 实际中,主要有两种方法处理大量的并发任务,一种是一个请求由系统产生一个相应的处理请求的线程(一对一) 另外一种是系统预先生成一些用于处理请求的进程,当请 ...
- 使用C++11实现一个半同步半异步线程池
前言 C++11之前我们使用线程需要系统提供API.posix线程库或者使用boost提供的线程库,C++11后就加入了跨平台的线程类std::thread,线程同步相关类std::mutex.std ...
- c++11 实现半同步半异步线程池
感受: 随着深入学习,现代c++给我带来越来越多的惊喜- c++真的变强大了. 半同步半异步线程池: 事实上非常好理解.分为三层 同步层:通过IO复用或者其它多线程多进程等不断的将待处理事件加入到队列 ...
- Spring Boot系列二 Spring @Async异步线程池用法总结
1. TaskExecutor Spring异步线程池的接口类,其实质是java.util.concurrent.Executor Spring 已经实现的异常线程池: 1. SimpleAsyncT ...
- (原创)C++半同步半异步线程池2
(原创)C++半同步半异步线程池 c++11 boost技术交流群:296561497,欢迎大家来交流技术. 线程池可以高效的处理任务,线程池中开启多个线程,等待同步队列中的任务到来,任务到来多个线程 ...
随机推荐
- Ubuntu安装Git及Git配置
1.检查Git是否已经安装 使用git version,若不显示版本号则Git未安装,下面是我安装好后显示的版本号 2.安装Git sudo apt-get install git Centos使用y ...
- Jmeter环境变量配置你不得不知道的事情
在安装Jmeter的过程中大家肯定需要配置环境,但是为什么要配置JDK的环境变量呢?大家有没有好奇过,有没有仔细去像一下呢,其实在安装Jmeter前,大家应该都知道Jmeter是我们JAVA开发的,J ...
- [算法笔记-题解]问题 C: 例题4-3 比较交换3个实数值,并按序输出
问题 C: 例题4-3 比较交换3个实数值,并按序输出 [命题人 : 外部导入] 时间限制 : 1.000 sec 内存限制 : 12 MB 题目描述 从键盘输入3个实数a, b, c,通过比较交换, ...
- 接口测试 再也不必来回切换,发现一个接口测试软件,可以替代 Swagger+Mock+Jmeter+Postman
前言 日常测试过程中,常常需要多种工具来接力完成自己的接口测试任务. 比如说, 使用swagger查看接口文档, 使用mock编造接口数据对前端页面做测试 使用postman测试后端接口, 用Jm ...
- Android系统编程入门系列之硬件交互——通信硬件USB
在硬件交互的首篇对设备硬件的分类中,互联通信系列硬件主要用来与其他设备进行数据交互.从本文开始,将重点介绍该系列相关硬件. 互联通信系列硬件 根据硬件的可通信距离,由近及远分为USB.NFC.蓝牙.W ...
- Nginx日志配置及日志分析脚本案例
https://blog.csdn.net/bbwangj/article/details/82186162 nginx的log日志分为access log 和 error log 其中access ...
- c# - 一个.cs类文件里如何建多个类
方法类可以使用 internal 修饰符,意为接口类, 主函数建议添加私有修饰符 private 控制台打印
- Jquery通过遍历数组给checkbox赋默认值
需求:有一个数组:(北京菜,粤菜),checkbox如下: 现在想通过遍历这个数组,使数组里包含的值,在checkbox选中 代码: var flavors = new Array([北京菜 , 粤菜 ...
- react组件性能优化PureComponent
首先我们使用react组件会配合connect来连接store获取state,那么只要store中的state发生改变组件就会重新渲染,所以性能不高,一般我们可以使用shouldComponentUp ...
- Go语言实战-爬取校花网图片
一.目标网站分析 爬取校花网http://www.xiaohuar.com/大学校花所有图片. 经过分析,所有图片分为四个页面,http://www.xiaohuar.com/list-1-0.htm ...