溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

java線程池如何合理設(shè)置最大線程數(shù)和核心線程數(shù)

發(fā)布時間:2021-12-28 17:09:30 來源:億速云 閱讀:783 作者:小新 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)java線程池如何合理設(shè)置最大線程數(shù)和核心線程數(shù),小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

線程池合理設(shè)置最大線程數(shù)和核心線程數(shù)

工作中有這樣一個場景,需要處理千萬級別的數(shù)據(jù)的一個算法,大部分是增刪查的操作。這個時候就需要使用多線程去處理。

一開始是這么配置的

@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);//隊列最大容量
        //當(dāng)提交的任務(wù)個數(shù)大于QueueCapacity,就需要設(shè)置該參數(shù),但spring提供的都不太滿足業(yè)務(wù)場景,可以自定義一個,也可以注意不要超過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ù)越來越多,處理速度也隨之降低,跑個一兩天之后,差不多能夠處理10萬多。完全滿足不了需求。

后來網(wǎng)上查詢線程池核心數(shù)配置

大部分都是這樣的:

注:IO密集型(某大廠實踐經(jīng)驗) 核心線程數(shù) = CPU核數(shù) / (1-阻塞系數(shù))或著 CPU密集型:核心線程數(shù) = CPU核數(shù) + 1 IO密集型:核心線程數(shù) = CPU核數(shù) * 2

也嘗試著這么配置,結(jié)果發(fā)現(xiàn)效率并不理想,提高不了多少。

最后我是這么配置的

結(jié)果效率大大提升,僅用不到一天的數(shù)據(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);//隊列最大容量
        //當(dāng)提交的任務(wù)個數(shù)大于QueueCapacity,就需要設(shè)置該參數(shù),但spring提供的都不太滿足業(yè)務(wù)場景,可以自定義一個,也可以注意不要超過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ù)到線程池時,

  • 第一步:先判斷線程池中當(dāng)前線程數(shù)量是否達(dá)到了corePoolSize,若未達(dá)到,則新建線程運(yùn)行此任務(wù),且任務(wù)結(jié)束后將該線程保留在線程池中,不做銷毀處理,若當(dāng)前線程數(shù)量已達(dá)到corePoolSize,則進(jìn)入下一步;

  • 第二步:判斷工作隊列(workQueue)是否已滿,未滿則將新的任務(wù)提交到工作隊列中,滿了則進(jìn)入下一步;

  • 第三步:判斷線程池中的線程數(shù)量是否達(dá)到了maxumunPoolSize,如果未達(dá)到,則新建一個工作線程來執(zhí)行這個任務(wù),如果達(dá)到了則使用飽和策略來處理這個任務(wù)。注意: 在線程池中的線程數(shù)量超過corePoolSize時,每當(dāng)有線程的空閑時間超過了keepAliveTime,這個線程就會被終止。直到線程池中線程的數(shù)量不大于corePoolSize為止。

(由第三步可知,在一般情況下,Java線程池中會長期保持corePoolSize個線程。)

飽和策略

當(dāng)工作隊列滿且線程個數(shù)達(dá)到maximunPoolSize后所采取的策略

  • AbortPolicy:默認(rèn)策略;新任務(wù)提交時直接拋出未檢查的異常RejectedExecutionException,該異常可由調(diào)用者捕獲。

  • CallerRunsPolicy:既不拋棄任務(wù)也不拋出異常,使用調(diào)用者所在線程運(yùn)行新的任務(wù)。

  • DiscardPolicy:丟棄新的任務(wù),且不拋出異常。

  • DiscardOldestPolicy:調(diào)用poll方法丟棄工作隊列隊頭的任務(wù),然后嘗試提交新任務(wù)

  • 自定義策略:根據(jù)用戶需要定制。

關(guān)于“java線程池如何合理設(shè)置最大線程數(shù)和核心線程數(shù)”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI