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,欢迎大家来交流技术. 线程池可以高效的处理任务,线程池中开启多个线程,等待同步队列中的任务到来,任务到来多个线程 ...
随机推荐
- BST的中序后继
二叉搜索树中的顺序后继:从BST中找到指定节点的下一个节点. 比如1的下一个是2,2的下一个是3,4的下一个是5. 思路: 方法1:递归执行中序遍历,获取list,得到p的下一个.时间O(N),空间O ...
- 【LeetCode】43. Multiply Strings 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 1057 - Collecting Gold
1057 - Collecting Gold PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB ...
- uniapp以及微信小程序中scroll-view隐藏滚动条 自定义滚动条
隐藏滚动条 1.全局隐藏滚动条,在app.vue中 ::-webkit-scrollbar{ display: none; } 2.局部隐藏藏滚动条 样式没有使用scoped属性时, 否则无效. .u ...
- Java Web程序设计笔记 • 【第2章 JSP基础】
全部章节 >>>> 本章目录 2.1 JSP 简介 2.1.1 JSP 概述 2.1.2 开发第一个 JSP 页面 2.1.3 JSP 处理流程 2.1.4 实践练习 2. ...
- Java面向对象笔记 • 【第9章 JDBC编程】
全部章节 >>>> 本章目录 9.1 JDBC基础 9.1.1 JDBC简介 9.1.2 JDBC常用API简介 JDBC 常用API功能说明 9.1.3 JDBC编程步骤 ...
- vue grammer one
本文所有内容均来自 书籍<vue.js实战> 完整代码请查看github v-model <!DOCTYPE html> <html> <head> & ...
- vim 个性化设置
vim 编辑器安装 yum install vim vim个性化设置 vim ~/.vimrc 复制以下代码 关闭vim一致性原则 set nocompatible 显示行号 set number 设 ...
- maven pom.xml 的 spring-boot-maven-plugin 红色报错 解决
解决方法,添加对应的spring boot 版本号即可
- vscode 前端好用插件汇总
本篇文章根据实际开发中使用的扩展插件,结合<精选!15 个必备的 VSCode 插件(前端类)>.<vscode 插件推荐 - 献给所有前端工程师(2017.8.18更新)>中 ...