最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

SpringBoot使用異步線程池實(shí)現(xiàn)生產(chǎn)環(huán)境批量數(shù)據(jù)推送

 更新時(shí)間:2022年02月04日 11:23:24   作者:福隆苑居士  
本文主要介紹了SpringBoot使用異步線程池實(shí)現(xiàn)生產(chǎn)環(huán)境批量數(shù)據(jù)推送,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧

前言

SpringBoot使用異步線程池:

1、編寫線程池配置類,自定義一個(gè)線程池;

2、定義一個(gè)異步服務(wù);

3、使用@Async注解指向定義的線程池;

這里以我工作中使用過的一個(gè)案例來做描述,我所在公司是醫(yī)療行業(yè),敏感數(shù)據(jù)需要上報(bào)到某監(jiān)管平臺(tái),所以有一個(gè)定時(shí)任務(wù)在流量較小時(shí)(一般是凌晨后)執(zhí)行上報(bào)行為。但特殊時(shí)期會(huì)存在一定要在工作時(shí)間大批量上報(bào)數(shù)據(jù)的情況,且要求短時(shí)間內(nèi)就要完成,此時(shí)就考慮寫一個(gè)專門的異步上報(bào)接口手動(dòng)執(zhí)行,利用線程池上報(bào),極大提高了速度。

編寫線程池配置類

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 {
? ? /**
? ? ?* 定義數(shù)據(jù)上報(bào)線程池
? ? ?* @return
? ? ?*/
? ? @Bean("dataCollectionExecutor")
? ? public Executor dataCollectionExecutor() {
?
? ? ? ? ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
?
? ? ? ? // 核心線程數(shù)量:當(dāng)前機(jī)器的核心數(shù)
? ? ? ? executor.setCorePoolSize(
? ? ? ? ? ? ? ? Runtime.getRuntime().availableProcessors());
?
? ? ? ? // 最大線程數(shù)
? ? ? ? executor.setMaxPoolSize(
? ? ? ? ? ? ? ? Runtime.getRuntime().availableProcessors() * 2);
?
? ? ? ? // 隊(duì)列大小
? ? ? ? executor.setQueueCapacity(Integer.MAX_VALUE);
?
? ? ? ? // 線程池中的線程名前綴
? ? ? ? executor.setThreadNamePrefix("sjsb-");
?
? ? ? ? // 拒絕策略:直接拒絕
? ? ? ? executor.setRejectedExecutionHandler(
? ? ? ? ? ? ? ? new ThreadPoolExecutor.AbortPolicy());
?
? ? ? ? // 執(zhí)行初始化
? ? ? ? executor.initialize();
?
? ? ? ? return executor;
? ? }
}

 PS:

1)、需要注意,這里一定要自己定義ThreadPoolTaskExecutor線程池,否則springboot的異步注解會(huì)執(zhí)行默認(rèn)線程池,存在線程阻塞導(dǎo)致CPU飆高及內(nèi)存溢出的風(fēng)險(xiǎn)。這一點(diǎn)可以參考阿里開發(fā)手冊(cè),線程池定義這塊明確提到了這一點(diǎn);

2)、在@Bean注解中定義線程池名稱,后面異步注解會(huì)用到。

編寫異步服務(wù)

/**
?* 異步方法的服務(wù), 不影響主程序運(yùn)行。
?*/
@Service
public class AsyncService {
?
? ? private final Logger log = LoggerFactory.getLogger(AsyncService.class);
?
? ? /**
? ? ?* 發(fā)送短信
? ? ?*/
? ? @Async("sendMsgExecutor")
? ? public void sendMsg(String access_token, Consult item, Map<String, String> configMap) {
? ? ? ? // 此處編寫發(fā)送短信業(yè)務(wù)
? ? ? ? // 1、buildConsultData();
? ? ? ? // 2、sendMsg();
? ? }
?
? ? /**
? ? ?* 發(fā)送微信訂閱消息
? ? ?*/
? ? @Async
? ? public void sendSubscribeMsg(String access_token, Consult item, Map<String, String> configMap) {
? ? ? ? // 此處編寫發(fā)送微信訂閱消息業(yè)務(wù)
? ? ? ? // 1、buildConsultData();
? ? ? ? // 2、sendSubscribeMsg();
? ? }
?
? ? /**
? ? ?* 數(shù)據(jù)并上報(bào)
? ? ?*/
? ? @Async("dataCollectionExecutor")
? ? public void buildAndPostData(String access_token, Consult item, Map<String, String> configMap) {
? ? ? ? // 此處編寫上報(bào)業(yè)務(wù),如拼接數(shù)據(jù),然后執(zhí)行上報(bào)。
? ? ? ? // 1、buildConsultData();
? ? ? ? // 2、postData();
? ? }
}

PS:
1)、以上是代碼片段,個(gè)人經(jīng)驗(yàn)認(rèn)為專門定義一個(gè)異步service存放各個(gè)異步方法最佳,這樣可以避免編碼時(shí)一些誤操作比如異步方法不是void或者是private修飾,導(dǎo)致@Async注解失效的情況,同時(shí)可以安排每個(gè)注解指向不同的自定義線程池更加靈活;
2)、@Async注解中的名稱就是上面定義的自定義線程池名稱,這樣業(yè)務(wù)執(zhí)行時(shí)就會(huì)從指定線程池中獲取異步線程。

異步批量上報(bào)數(shù)據(jù)

@Autowired
private AsyncService asyncService;
?
/**
?* 手動(dòng)上報(bào)問診記錄,線程池方式。
?*/
public void manualUploadConsultRecordsAsync(String channel, Date startTime, Date endTime) {
?
? ? // 查詢指定時(shí)間內(nèi)的問診記錄
? ?List<Consult> consultList = consultService
? ? ? ?.findPaidListByChannelAndTime(channel, startTime, endTime, configMap.get("serviceId"));
?
? ?if (!CollectionUtils.isEmpty(consultList)) {
?
? ? ? ?log.debug("[SendWZDataService][manualUploadConsultRecordsAsync]>>>> 手動(dòng)上報(bào)問診記錄, 一共[{}]條", consultList.size());
?
? ? ? ?consultList.forEach((item) -> {
? ? ? ? ? ?try {
? ? ? ? ? ? ? ?// 異步調(diào)用,使用線程池。
? ? ? ? ? ? ? ?asyncService.buildAndPostData(access_token, item, configMap);
? ? ? ? ? ?} catch (Exception ex) {
? ? ? ? ? ? ? ?log.error("[SendWZDataService][manualUploadConsultRecordsAsync]>>>> 手動(dòng)上報(bào)問診記錄發(fā)生異常: ", ex);
? ? ? ? ? ?}
? ? ? ?});
? ?}
}

總結(jié)

以上方式已經(jīng)在生產(chǎn)環(huán)境運(yùn)行,在工作時(shí)間內(nèi)執(zhí)行過很多次,一次數(shù)萬條記錄基本是幾分鐘內(nèi)就全部上報(bào)完畢,而正常循環(huán)遍歷時(shí)一次大概需要半個(gè)小時(shí)左右。

線程池的使用方式往往來源于業(yè)務(wù)場景,如果類似的業(yè)務(wù)不存在緊急處理的情況,大體還是以任務(wù)調(diào)度執(zhí)行為主,因?yàn)楦踩?。如果存在緊急處理的情況,那么使用SpringBoot+線程池的方式不僅能節(jié)省非常多的時(shí)間,且不占用主線程的執(zhí)行空間。

到此這篇關(guān)于SpringBoot使用異步線程池實(shí)現(xiàn)生產(chǎn)環(huán)境批量數(shù)據(jù)推送的文章就介紹到這了,更多相關(guān)SpringBoot 生產(chǎn)環(huán)境批量數(shù)據(jù)推送內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

聂荣县| 平度市| 波密县| 枣庄市| 和田市| 托里县| 肃南| 海淀区| 阿尔山市| 宣城市| 建宁县| 德清县| 二连浩特市| 海南省| 当雄县| 石阡县| 莲花县| 突泉县| 布尔津县| 库尔勒市| 镇原县| 微山县| 德兴市| 深水埗区| 大新县| 灌云县| 宾川县| 平和县| 浪卡子县| 修水县| 金川县| 乌拉特前旗| 东平县| 江孜县| 永和县| 西平县| 苏尼特右旗| 新乐市| 新干县| 白河县| 香河县|