java線程池合理設置最大線程數和核心線程數方式
線程池合理設置最大線程數和核心線程數
工作中有這樣一個場景,需要處理千萬級別的數據的一個算法,大部分是增刪查的操作。這個時候就需要使用多線程去處理。
一開始是這麼配置的
@Configuration @EnableAsync(proxyTargetClass = true)//利用@EnableAsync註解開啟異步任務支持 @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);//隊列最大容量 //當提交的任務個數大於QueueCapacity,就需要設置該參數,但spring提供的都不太滿足業務場景,可以自定義一個,也可以註意不要超過QueueCapacity即可 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.setAwaitTerminationSeconds(10); taskExecutor.setThreadNamePrefix("BCarLogo-Thread-"); taskExecutor.initialize(); return taskExecutor; } }
這樣配置效率很低,一天大概能處理30多萬的數據。往後隨著插入表的數據越來越多,處理速度也隨之降低,跑個一兩天之後,差不多能夠處理10萬多。完全滿足不瞭需求。
後來網上查詢線程池核心數配置
大部分都是這樣的:
註:IO密集型(某大廠實踐經驗) 核心線程數 = CPU核數 / (1-阻塞系數)或著 CPU密集型:核心線程數 = CPU核數 + 1 IO密集型:核心線程數 = CPU核數 * 2
也嘗試著這麼配置,結果發現效率並不理想,提高不瞭多少。
最後我是這麼配置的
結果效率大大提升,僅用不到一天的數據,就跑完瞭千萬級的數據。
//獲取當前機器的核數 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);//隊列最大容量 //當提交的任務個數大於QueueCapacity,就需要設置該參數,但spring提供的都不太滿足業務場景,可以自定義一個,也可以註意不要超過QueueCapacity即可 taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); taskExecutor.setWaitForTasksToCompleteOnShutdown(true); taskExecutor.setAwaitTerminationSeconds(60); taskExecutor.setThreadNamePrefix("BCarLogo-Thread-"); taskExecutor.initialize(); return taskExecutor; }
完美的解決瞭問題!
線程池核心線程數與最大線程數的區別
線程池策略
corePoolSize:核心線程數;maximunPoolSize:最大線程數
每當有新的任務到線程池時,
- 第一步:先判斷線程池中當前線程數量是否達到瞭corePoolSize,若未達到,則新建線程運行此任務,且任務結束後將該線程保留在線程池中,不做銷毀處理,若當前線程數量已達到corePoolSize,則進入下一步;
- 第二步:判斷工作隊列(workQueue)是否已滿,未滿則將新的任務提交到工作隊列中,滿瞭則進入下一步;
- 第三步:判斷線程池中的線程數量是否達到瞭maxumunPoolSize,如果未達到,則新建一個工作線程來執行這個任務,如果達到瞭則使用飽和策略來處理這個任務。註意: 在線程池中的線程數量超過corePoolSize時,每當有線程的空閑時間超過瞭keepAliveTime,這個線程就會被終止。直到線程池中線程的數量不大於corePoolSize為止。
(由第三步可知,在一般情況下,Java線程池中會長期保持corePoolSize個線程。)
飽和策略
當工作隊列滿且線程個數達到maximunPoolSize後所采取的策略
AbortPolicy
:默認策略;新任務提交時直接拋出未檢查的異常RejectedExecutionException,該異常可由調用者捕獲。CallerRunsPolicy
:既不拋棄任務也不拋出異常,使用調用者所在線程運行新的任務。DiscardPolicy
:丟棄新的任務,且不拋出異常。DiscardOldestPolicy
:調用poll方法丟棄工作隊列隊頭的任務,然後嘗試提交新任務自定義策略
:根據用戶需要定制。
以上為個人經驗,希望能給大傢一個參考,也希望大傢多多支持WalkonNet。
推薦閱讀:
- springboot使用線程池(ThreadPoolTaskExecutor)示例
- SpringBoot 如何實現異步編程
- Java線程池中的各個參數如何合理設置
- 關於java中@Async異步調用詳細解析附代碼
- springboot創建線程池的兩種方式小結