java線程池合理設(shè)置最大線程數(shù)和核心線程數(shù)方式
線程池合理設(shè)置最大線程數(shù)和核心線程數(shù)
工作中有這樣一個(gè)場景,需要處理千萬級(jí)別的數(shù)據(jù)的一個(gè)算法,大部分是增刪查的操作。這個(gè)時(shí)候就需要使用多線程去處理。
一開始是這么配置的
@Configuration @EnableAsync(proxyTargetClass = true)//利用@EnableAsync注解開啟異步任務(wù)支持 @ComponentScan({"com.ctfojt.auditbcarslogo.service"}) //必須加此注解掃描包 public class ThreadPoolConfig implements AsyncConfigurer { @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(10);//核心線程大小 taskExecutor.setMaxPoolSize(20);//最大線程大小 taskExecutor.setQueueCapacity(500);//隊(duì)列最大容量 //當(dāng)提交的任務(wù)個(gè)數(shù)大于QueueCapacity,就需要設(shè)置該參數(shù),但spring提供的都不太滿足業(yè)務(wù)場景,可以自定義一個(gè),也可以注意不要超過QueueCapacity即可 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.setAwaitTerminationSeconds(10); taskExecutor.setThreadNamePrefix("BCarLogo-Thread-"); taskExecutor.initialize(); return taskExecutor; } }
這樣配置效率很低,一天大概能處理30多萬的數(shù)據(jù)。往后隨著插入表的數(shù)據(jù)越來越多,處理速度也隨之降低,跑個(gè)一兩天之后,差不多能夠處理10萬多。完全滿足不了需求。
后來網(wǎng)上查詢線程池核心數(shù)配置
大部分都是這樣的:
注:IO密集型(某大廠實(shí)踐經(jīng)驗(yàn)) 核心線程數(shù) = CPU核數(shù) / (1-阻塞系數(shù))或著 CPU密集型:核心線程數(shù) = CPU核數(shù) + 1 IO密集型:核心線程數(shù) = CPU核數(shù) * 2
也嘗試著這么配置,結(jié)果發(fā)現(xiàn)效率并不理想,提高不了多少。
最后我是這么配置的
結(jié)果效率大大提升,僅用不到一天的數(shù)據(jù),就跑完了千萬級(jí)的數(shù)據(jù)。
//獲取當(dāng)前機(jī)器的核數(shù) public static final int cpuNum = Runtime.getRuntime().availableProcessors(); @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(cpuNum);//核心線程大小 taskExecutor.setMaxPoolSize(cpuNum * 2);//最大線程大小 taskExecutor.setQueueCapacity(500);//隊(duì)列最大容量 //當(dāng)提交的任務(wù)個(gè)數(shù)大于QueueCapacity,就需要設(shè)置該參數(shù),但spring提供的都不太滿足業(yè)務(wù)場景,可以自定義一個(gè),也可以注意不要超過QueueCapacity即可 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.setAwaitTerminationSeconds(60); taskExecutor.setThreadNamePrefix("BCarLogo-Thread-"); taskExecutor.initialize(); return taskExecutor; }
完美的解決了問題!
線程池核心線程數(shù)與最大線程數(shù)的區(qū)別
線程池策略
corePoolSize:核心線程數(shù);maximunPoolSize:最大線程數(shù)
每當(dāng)有新的任務(wù)到線程池時(shí),
- 第一步:先判斷線程池中當(dāng)前線程數(shù)量是否達(dá)到了corePoolSize,若未達(dá)到,則新建線程運(yùn)行此任務(wù),且任務(wù)結(jié)束后將該線程保留在線程池中,不做銷毀處理,若當(dāng)前線程數(shù)量已達(dá)到corePoolSize,則進(jìn)入下一步;
- 第二步:判斷工作隊(duì)列(workQueue)是否已滿,未滿則將新的任務(wù)提交到工作隊(duì)列中,滿了則進(jìn)入下一步;
- 第三步:判斷線程池中的線程數(shù)量是否達(dá)到了maxumunPoolSize,如果未達(dá)到,則新建一個(gè)工作線程來執(zhí)行這個(gè)任務(wù),如果達(dá)到了則使用飽和策略來處理這個(gè)任務(wù)。注意: 在線程池中的線程數(shù)量超過corePoolSize時(shí),每當(dāng)有線程的空閑時(shí)間超過了keepAliveTime,這個(gè)線程就會(huì)被終止。直到線程池中線程的數(shù)量不大于corePoolSize為止。
(由第三步可知,在一般情況下,Java線程池中會(huì)長期保持corePoolSize個(gè)線程。)
飽和策略
當(dāng)工作隊(duì)列滿且線程個(gè)數(shù)達(dá)到maximunPoolSize后所采取的策略
AbortPolicy
:默認(rèn)策略;新任務(wù)提交時(shí)直接拋出未檢查的異常RejectedExecutionException,該異常可由調(diào)用者捕獲。CallerRunsPolicy
:既不拋棄任務(wù)也不拋出異常,使用調(diào)用者所在線程運(yùn)行新的任務(wù)。DiscardPolicy
:丟棄新的任務(wù),且不拋出異常。DiscardOldestPolicy
:調(diào)用poll方法丟棄工作隊(duì)列隊(duì)頭的任務(wù),然后嘗試提交新任務(wù)自定義策略
:根據(jù)用戶需要定制。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出
這篇文章主要給大家介紹了關(guān)于Java使用EasyExcel實(shí)現(xiàn)Excel的導(dǎo)入導(dǎo)出,在各種系統(tǒng)中,導(dǎo)入導(dǎo)出的數(shù)據(jù)一般都是通過Excel來完成的,需要的朋友可以參考下2023-07-07基于String不可變字符與StringBuilder可變字符的效率問題
這篇文章主要介紹了String不可變字符與StringBuilder可變字符的效率問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解
這篇文章主要介紹了Spring中屬性注入的幾種方式以及復(fù)雜屬性的注入詳解,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-04-04SpringBoot之Java配置的實(shí)現(xiàn)
這篇文章主要介紹了SpringBoot之Java配置的實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-01-01