亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

java線程池不同場(chǎng)景下使用示例經(jīng)驗(yàn)總結(jié)

 更新時(shí)間:2022年03月11日 11:30:21   作者:Q.E.D.  
這篇文章主要為大家介紹了java線程池不同場(chǎng)景如何使用的示例源碼及經(jīng)驗(yàn)總結(jié),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步

引導(dǎo)語(yǔ)

ThreadPoolExecutor 初始化時(shí),主要有如下幾個(gè)參數(shù):

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {

大家對(duì)這幾個(gè)參數(shù)應(yīng)該都很熟悉了,雖然參數(shù)很少,但實(shí)際工作中卻有很多門道,大多數(shù)的問題主要集中在線程大小的設(shè)置,隊(duì)列大小的設(shè)置兩方面上,接下來我們一起看看工作中,如何初始化 ThreadPoolExecutor。

1、coreSize == maxSize

我相信很多人都看過,或自己寫過這樣的代碼:

ThreadPoolExecutor executor = new ThreadPoolExecutor(10, 10, 600000L, TimeUnit.DAYS,
                                                     new LinkedBlockingQueue());

這行代碼主要展示了在初始化 ThreadPoolExecutor 的時(shí)候,coreSize 和 maxSize 是相等的,這樣設(shè)置的話,隨著請(qǐng)求的不斷增加,會(huì)是這樣的現(xiàn)象:

  • 請(qǐng)求數(shù) < coreSize 時(shí),新增線程;
  • 請(qǐng)求數(shù) >= coreSize && 隊(duì)列不滿時(shí),添加任務(wù)入隊(duì);
  • 隊(duì)列滿時(shí),此時(shí)因?yàn)?coreSize 和 maxSize 相等,任務(wù)會(huì)被直接拒絕。

這么寫的最大目的:是想讓線程一下子增加到 maxSize,并且不要回收線程,防止線程回收,避免不斷增加回收的損耗,一般來說業(yè)務(wù)流量都有波峰低谷,在流量低谷時(shí),線程不會(huì)被回收;流量波峰時(shí),maxSize 的線程可以應(yīng)對(duì)波峰,不需要慢慢初始化到 maxSize 的過程。

這樣設(shè)置有兩個(gè)前提條件:

allowCoreThreadTimeOut 我們采取默認(rèn) false,而不會(huì)主動(dòng)設(shè)置成 true,allowCoreThreadTimeOut 是 false 的話,當(dāng)線程空閑時(shí),就不會(huì)回收核心線程;

keepAliveTime 和 TimeUnit 我們都會(huì)設(shè)置很大,這樣線程空閑的時(shí)間就很長(zhǎng),線程就不會(huì)輕易的被回收。

我們現(xiàn)在機(jī)器的資源都是很充足的,我們不用去擔(dān)心線程空閑會(huì)浪費(fèi)機(jī)器的資源,所以這種寫法目前是很常見的。

2、maxSize 無界 + SynchronousQueue

在線程池選擇隊(duì)列時(shí),我們也會(huì)看到有同學(xué)選擇 SynchronousQueue,SynchronousQueue 我們?cè)?《SynchronousQueue 源碼解析》章節(jié)有說過,其內(nèi)部有堆棧和隊(duì)列兩種形式,默認(rèn)是堆棧的形式,其內(nèi)部是沒有存儲(chǔ)的容器的,放元素和拿元素是一一對(duì)應(yīng)的,比如我使用 put 方法放元素,如果此時(shí)沒有對(duì)應(yīng)的 take 操作的話,put 操作就會(huì)阻塞,需要有線程過來執(zhí)行 take 操作后,put 操作才會(huì)返回。

基于此特點(diǎn),如果要使用 SynchronousQueue 的話,我們需要盡量將 maxSize 設(shè)置大一點(diǎn),這樣就可以接受更多的請(qǐng)求。

假設(shè)我們?cè)O(shè)置 maxSize 是 10 的話,選擇 SynchronousQueue 隊(duì)列,假設(shè)所有請(qǐng)求都執(zhí)行 put 操作,沒有請(qǐng)求執(zhí)行 take 操作,前 10 個(gè) put 請(qǐng)求會(huì)消耗 10 個(gè)線程,都阻塞在 put 操作上,第 11 個(gè)請(qǐng)求過來后,請(qǐng)求就會(huì)被拒絕,所以我們才說盡量把 maxSize 設(shè)置大一點(diǎn),防止請(qǐng)求被拒絕。

maxSize 無界 + SynchronousQueue 這樣的組合方式優(yōu)缺點(diǎn)都很明顯:

優(yōu)點(diǎn):

當(dāng)任務(wù)被消費(fèi)時(shí),才會(huì)返回,這樣請(qǐng)求就能夠知道當(dāng)前請(qǐng)求是已經(jīng)在被消費(fèi)了,如果是其他的隊(duì)列的話,我們只知道任務(wù)已經(jīng)被提交成功了,但無法知道當(dāng)前任務(wù)是在被消費(fèi)中,還是正在隊(duì)列中堆積。

缺點(diǎn):

比較消耗資源,大量請(qǐng)求到來時(shí),我們會(huì)新建大量的線程來處理請(qǐng)求;

如果請(qǐng)求的量難以預(yù)估的話,maxSize 的大小也很難設(shè)置。

3、maxSize 有界 + Queue 無界

在一些對(duì)實(shí)時(shí)性要求不大,但流量忽高忽低的場(chǎng)景下,可以使用 maxSize 有界 + Queue 無界的組合方式。

比如我們?cè)O(shè)置 maxSize 為 20,Queue 選擇默認(rèn)構(gòu)造器的 LinkedBlockingQueue,這樣做的優(yōu)缺點(diǎn)如下:

優(yōu)點(diǎn):

電腦 cpu 固定的情況下,每秒能同時(shí)工作的線程數(shù)是有限的,此時(shí)開很多的線程其實(shí)也是浪費(fèi),還不如把這些請(qǐng)求放到隊(duì)列中去等待,這樣可以減少線程之間的 CPU 的競(jìng)爭(zhēng);

LinkedBlockingQueue 默認(rèn)構(gòu)造器構(gòu)造出來的鏈表的最大容量是 Integer 的最大值,非常適合流量忽高忽低的場(chǎng)景,當(dāng)流量高峰時(shí),大量的請(qǐng)求被阻塞在隊(duì)列中,讓有限的線程可以慢慢消費(fèi)。

缺點(diǎn):

流量高峰時(shí),大量的請(qǐng)求被阻塞在隊(duì)列中,對(duì)于請(qǐng)求的實(shí)時(shí)性難以保證,所以當(dāng)對(duì)請(qǐng)求的實(shí)時(shí)性要求較高的場(chǎng)景,不能使用該組合。

4、maxSize 有界 + Queue 有界

這種組合是對(duì) 3 缺點(diǎn)的補(bǔ)充,我們把隊(duì)列從無界修改成有界,只要排隊(duì)的任務(wù)在要求的時(shí)間內(nèi),能夠完成任務(wù)即可。

這種組合需要我們把線程和隊(duì)列的大小進(jìn)行配合計(jì)算,保證大多數(shù)請(qǐng)求都可以在要求的時(shí)間內(nèi),有響應(yīng)返回。

5、keepAliveTime 設(shè)置無窮大

有些場(chǎng)景下我們不想讓空閑的線程被回收,于是就把 keepAliveTime 設(shè)置成 0,實(shí)際上這種設(shè)置是錯(cuò)誤的,當(dāng)我們把 keepAliveTime 設(shè)置成 0 時(shí),線程使用 poll 方法在隊(duì)列上進(jìn)行超時(shí)阻塞時(shí),會(huì)立馬返回 null,也就是空閑線程會(huì)立馬被回收。

所以如果我們想要空閑的線程不被回收,我們可以設(shè)置 keepAliveTime 為無窮大值,并且設(shè)置 TimeUnit 為時(shí)間的大單位,比如我們?cè)O(shè)置 keepAliveTime 為 365,TimeUnit 為 TimeUnit.DAYS,意思是線程空閑 1 年內(nèi)都不會(huì)被回收。

在實(shí)際的工作中,機(jī)器的內(nèi)存一般都?jí)虼?,我們合理設(shè)置 maxSize 后,即使線程空閑,我們也不希望線程被回收,我們常常也會(huì)設(shè)置 keepAliveTime 為無窮大。

6、線程池的公用和獨(dú)立

在實(shí)際工作中,某一個(gè)業(yè)務(wù)下的所有場(chǎng)景,我們都不會(huì)公用一個(gè)線程池,一般有以下幾個(gè)原則:

查詢和寫入不公用線程池,互聯(lián)網(wǎng)應(yīng)用一般來說,查詢量遠(yuǎn)遠(yuǎn)大于寫入的量,如果查詢和寫入都要走線程池的話,我們一定不要公用線程池,也就是說查詢走查詢的線程池,寫入走寫入的線程池,如果公用的話,當(dāng)查詢量很大時(shí),寫入的請(qǐng)求可能會(huì)到隊(duì)列中去排隊(duì),無法及時(shí)被處理;

多個(gè)寫入業(yè)務(wù)場(chǎng)景看情況是否需要公用線程池,原則上來說,每個(gè)業(yè)務(wù)場(chǎng)景都獨(dú)自使用自己的線程池,絕不共用,這樣在業(yè)務(wù)治理、限流、熔斷方面都比較容易,一旦多個(gè)業(yè)務(wù)場(chǎng)景公用線程池,可能就會(huì)造成業(yè)務(wù)場(chǎng)景之間的互相影響,現(xiàn)在的機(jī)器內(nèi)存都很大,每個(gè)寫入業(yè)務(wù)場(chǎng)景獨(dú)立使用自己的線程池也是比較合理的;

多個(gè)查詢業(yè)務(wù)場(chǎng)景是可以公用線程池的,查詢的請(qǐng)求一般來說有幾個(gè)特點(diǎn):查詢的場(chǎng)景多、rt 時(shí)間短、查詢的量比較大,如果給每個(gè)查詢場(chǎng)景都弄一個(gè)單獨(dú)的線程池的話,第一個(gè)比較耗資源,第二個(gè)很難定義線程池中線程和隊(duì)列的大小,比較復(fù)雜,所以多個(gè)相似的查詢業(yè)務(wù)場(chǎng)景是可以公用線程池的。

7、如何算線程大小和隊(duì)列大小

在實(shí)際的工作中,我們使用線程池時(shí),需要慎重考慮線程的大小和隊(duì)列的大小,主要從幾個(gè)方面入手:

  • 根據(jù)業(yè)務(wù)進(jìn)行考慮,初始化線程池時(shí),我們需要考慮所有業(yè)務(wù)涉及的線程池,如果目前所有的業(yè)務(wù)同時(shí)都有很大流量,那么在對(duì)于當(dāng)前業(yè)務(wù)設(shè)置線程池時(shí),我們盡量把線程大小、隊(duì)列大小都設(shè)置小,如果所有業(yè)務(wù)基本上都不會(huì)同時(shí)有流量,那么就可以稍微設(shè)置大一點(diǎn);
  • 根據(jù)業(yè)務(wù)的實(shí)時(shí)性要求,如果實(shí)時(shí)性要求高的話,我們把隊(duì)列設(shè)置小一點(diǎn),coreSize == maxSize,并且設(shè)置 maxSize 大一點(diǎn),如果實(shí)時(shí)性要求低的話,就可以把隊(duì)列設(shè)置大一點(diǎn)。

假設(shè)現(xiàn)在機(jī)器上某一時(shí)間段只會(huì)運(yùn)行一種業(yè)務(wù),業(yè)務(wù)的實(shí)時(shí)性要求較高,每個(gè)請(qǐng)求的平均 rt 是 200ms,請(qǐng)求超時(shí)時(shí)間是 2000ms,機(jī)器是 4 核 CPU,內(nèi)存 16G,一臺(tái)機(jī)器的 qps 是 100,這時(shí)候我們可以模擬一下如何設(shè)置:

4 核 CPU,假設(shè) CPU 能夠跑滿,每個(gè)請(qǐng)求的 rt 是 200ms,就是 200 ms 能執(zhí)行 4 條請(qǐng)求,2000ms 內(nèi)能執(zhí)行 2000/200 * 4 = 40 條請(qǐng)求;

200 ms 能執(zhí)行 4 條請(qǐng)求,實(shí)際上 4 核 CPU 的性能遠(yuǎn)遠(yuǎn)高于這個(gè),我們可以拍腦袋加 10 條,也就是說 2000ms 內(nèi)預(yù)估能夠執(zhí)行 50 條;

一臺(tái)機(jī)器的 qps 是 100,此時(shí)我們計(jì)算一臺(tái)機(jī)器 2 秒內(nèi)最多處理 50 條請(qǐng)求,所以此時(shí)如果不進(jìn)行 rt 優(yōu)化的話,我們需要加至少一臺(tái)機(jī)器。

線程池可以大概這么設(shè)置:

ThreadPoolExecutor executor = new ThreadPoolExecutor(15, 15, 365L, TimeUnit.DAYS,
                                                     new LinkedBlockingQueue(35));

線程數(shù)最大為 15,隊(duì)列最大為 35,這樣機(jī)器差不多可以在 2000ms 內(nèi)處理最大的請(qǐng)求 50 條,當(dāng)然根據(jù)你機(jī)器的性能和實(shí)時(shí)性要求,你可以調(diào)整線程數(shù)和隊(duì)列的大小占比,只要總和小于 50 即可。

以上只是很粗糙的設(shè)置,在實(shí)際的工作中,還需要根據(jù)實(shí)際情況不斷的觀察和調(diào)整。

8、總結(jié)

線程池設(shè)置非常重要,我們盡量少用 Executors 類提供的各種初始化線程池的方法,多根據(jù)業(yè)務(wù)的量,實(shí)時(shí)性要求來計(jì)算機(jī)器的預(yù)估承載能力,設(shè)置預(yù)估的線程和隊(duì)列大小,并且根據(jù)實(shí)時(shí)請(qǐng)求不斷的調(diào)整線程池的大小值。

以上就是java線程池不同場(chǎng)景下使用示例經(jīng)驗(yàn)總結(jié)的詳細(xì)內(nèi)容,更多關(guān)于java線程池不同場(chǎng)景使用經(jīng)驗(yàn)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 基于Jmeter生成測(cè)試報(bào)告過程圖解

    基于Jmeter生成測(cè)試報(bào)告過程圖解

    這篇文章主要介紹了基于Jmeter生成測(cè)試報(bào)告過程圖解,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • IDEA項(xiàng)目中配置Maven鏡像源(下載源)的詳細(xì)過程

    IDEA項(xiàng)目中配置Maven鏡像源(下載源)的詳細(xì)過程

    Maven是一個(gè)能使我們的java程序開發(fā)節(jié)省時(shí)間和精力,是開發(fā)變得相對(duì)簡(jiǎn)單,還能使開發(fā)規(guī)范化的工具,下面這篇文章主要給大家介紹了關(guān)于IDEA項(xiàng)目中配置Maven鏡像源(下載源)的詳細(xì)過程,需要的朋友可以參考下
    2024-02-02
  • 淺談springboot一個(gè)service內(nèi)組件的加載順序

    淺談springboot一個(gè)service內(nèi)組件的加載順序

    這篇文章主要介紹了springboot一個(gè)service內(nèi)組件的加載順序,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家
    2021-08-08
  • Druid之連接創(chuàng)建及銷毀示例詳解

    Druid之連接創(chuàng)建及銷毀示例詳解

    這篇文章主要為大家介紹了Druid之連接創(chuàng)建及銷毀示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Maven實(shí)現(xiàn)自己的starter依賴

    Maven實(shí)現(xiàn)自己的starter依賴

    本文主要介紹了Maven實(shí)現(xiàn)自己的starter依賴,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • 淺談常用字符串與集合類轉(zhuǎn)換的工具類

    淺談常用字符串與集合類轉(zhuǎn)換的工具類

    下面小編就為大家?guī)硪黄獪\談常用字符串與集合類轉(zhuǎn)換的工具類。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2016-08-08
  • RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例

    RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例

    這篇文章主要為大家介紹了RocketMQ的push消費(fèi)方式實(shí)現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪<BR>
    2022-08-08
  • Spring Cloud Alibaba Nacos Config進(jìn)階使用

    Spring Cloud Alibaba Nacos Config進(jìn)階使用

    這篇文章主要介紹了Spring Cloud Alibaba Nacos Config進(jìn)階使用,文中使用企業(yè)案例,圖文并茂的展示了Nacos Config的使用,感興趣的小伙伴可以看一看
    2021-08-08
  • Maven Repository倉(cāng)庫(kù)的具體使用

    Maven Repository倉(cāng)庫(kù)的具體使用

    本文主要介紹了Maven Repository倉(cāng)庫(kù)的具體使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • 新的Java訪問mysql數(shù)據(jù)庫(kù)工具類的操作代碼

    新的Java訪問mysql數(shù)據(jù)庫(kù)工具類的操作代碼

    本文通過實(shí)例代碼給大家介紹新的Java訪問mysql數(shù)據(jù)庫(kù)工具類的方法,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-12-12

最新評(píng)論