java的線程池框架及線程池的原理
java 線程池詳解
什么是線程池?
提供一組線程資源用來(lái)復(fù)用線程資源的一個(gè)池子
為什么要用線程池?
線程的資源是有限的,當(dāng)處理一組業(yè)務(wù)的時(shí)候,我們需要不斷的創(chuàng)建和銷(xiāo)毀線程,大多數(shù)情況下,我們需要反復(fù)的進(jìn)行大量的創(chuàng)建和銷(xiāo)毀工作,這個(gè)動(dòng)作對(duì)于服務(wù)器而言,也是很浪費(fèi)的一種情況,這時(shí)候我們可以利用線程池來(lái)復(fù)用這一部分已經(jīng)創(chuàng)建過(guò)的線程資源,避免不斷的創(chuàng)建和銷(xiāo)毀的動(dòng)作。
線程池的原理
創(chuàng)建好固定數(shù)量的線程,吧線程先存下來(lái),有任務(wù)提交的時(shí)候,把資源放到等待隊(duì)列中,等待線程池中的任務(wù)隊(duì)列不斷的去消費(fèi)處理這個(gè)隊(duì)列中的任務(wù)
java的線程池原理
有5個(gè)核心的屬性:最大線程數(shù)量,核心線程數(shù)量,等待隊(duì)列,任務(wù)隊(duì)列,拒絕策略
它的執(zhí)行流程是這樣的:
- 工作者workers數(shù)量低于核心工作者數(shù)corePoolSize時(shí)會(huì)優(yōu)先創(chuàng)建一個(gè)工作者worker處理job,處理成功則返回。
- 工作者workers數(shù)量高于核心工作者數(shù)時(shí)會(huì)優(yōu)先把job放入到待處理隊(duì)列,放入隊(duì)列成功時(shí)處理結(jié)束。
- 步驟2中入隊(duì)失敗會(huì)識(shí)別工作者數(shù)是否還小于最大工作者數(shù)maximumPoolsize,小于的話也會(huì)新創(chuàng)建一個(gè)工作者worker處理job。
- 執(zhí)行拒絕策略
java的線程池框架Executor
Executor里提供了4種類(lèi)型的線程池:
newCachedThreadPool
- 緩存型池子,先查看池中有沒(méi)有以前建立的線程,如果有,就 reuse.如果沒(méi)有,就建一個(gè)新的線程加入池中
- 緩存型池子通常用于執(zhí)行一些生存期很短的異步型任務(wù),因此在一些面向連接的daemon型SERVER中用得不多。但對(duì)于生存期短的異步任務(wù),它是Executor的首選。
- 能reuse的線程,必須是timeout IDLE內(nèi)的池中線程,缺省 timeout是60s,超過(guò)這個(gè)IDLE時(shí)長(zhǎng),線程實(shí)例將被終止及移出池。
注意,放入CachedThreadPool的線程不必?fù)?dān)心其結(jié)束,超過(guò)TIMEOUT不活動(dòng),其會(huì)自動(dòng)被終止。
newFixedThreadPool
- newFixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時(shí)建新的線程
- 其獨(dú)特之處:任意時(shí)間點(diǎn),最多只能有固定數(shù)目的活動(dòng)線程存在,此時(shí)如果有新的線程要建立,只能放在另外的隊(duì)列中等待,直到當(dāng)前的線程中某個(gè)線程終止直接被移出池子
- 和cacheThreadPool不同,F(xiàn)ixedThreadPool沒(méi)有IDLE機(jī)制(可能也有,但既然文檔沒(méi)提,肯定非常長(zhǎng),類(lèi)似依賴上層的TCP或UDP IDLE機(jī)制之類(lèi)的),所以FixedThreadPool多數(shù)針對(duì)一些很穩(wěn)定很固定的正規(guī)并發(fā)線程,多用于服務(wù)器
- 從方法的源代碼看,cache池和fixed 池調(diào)用的是同一個(gè)底層 池,只不過(guò)參數(shù)不同:fixed池線程數(shù)固定,并且是0秒IDLE(無(wú)IDLE),cache池線程數(shù)支持0-Integer.MAX_VALUE(顯然完全沒(méi)考慮主機(jī)的資源承受能力),60秒IDLE
newScheduledThreadPool
- 調(diào)度型線程池
- 這個(gè)池子里的線程可以按schedule依次delay執(zhí)行,或周期執(zhí)行
SingleThreadExecutor
- 單例線程,任意時(shí)間池中只能有一個(gè)線程
- 用的是和cache池和fixed池相同的底層池,但線程數(shù)目是1-1,0秒IDLE(無(wú)IDLE)
線程池調(diào)優(yōu)
一般來(lái)講對(duì)于一個(gè)線程池沒(méi)有固定的合適的參數(shù),只有通過(guò)不斷的去調(diào)整優(yōu)化參數(shù),找出最適合自己業(yè)務(wù)的參數(shù)才是最好的調(diào)優(yōu)方式,但是通常來(lái)講,線程池的初始化參數(shù)設(shè)置是有一定的公式可以借鑒的,在開(kāi)始業(yè)務(wù)不是足夠膨脹的時(shí)候,我們可以通過(guò)以下的公式來(lái)計(jì)算出自己的核心參數(shù)的設(shè)置。
首先我們要確認(rèn)業(yè)務(wù)類(lèi)型,不同的業(yè)務(wù)有不同的計(jì)算公式:
- CPU密集型任務(wù)配置盡可能少的線程數(shù)量:cpu+1
- IO密集型任務(wù)則由于需要等待IO操作,線程并不是一直在執(zhí)行任務(wù),則配置盡可能多的線程,如2*Ncpu。
- 混合型的任務(wù),如果可以拆分,則將其拆分成一個(gè)CPU密集型任務(wù)和一個(gè)IO密集型任務(wù),只要這兩個(gè)任務(wù)執(zhí)行的時(shí)間相差不是太大,那么分解后執(zhí)行的吞吐率要高于串行執(zhí)行的吞吐率,如果這兩個(gè)任務(wù)執(zhí)行時(shí)間相差太大,則沒(méi)必要進(jìn)行分解。我們可以通過(guò)Runtime.getRuntime().availableProcessors()方法獲得當(dāng)前設(shè)備的CPU個(gè)數(shù)。
感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
SpringBoot項(xiàng)目中使用Mockito的示例代碼
這篇文章主要介紹了SpringBoot項(xiàng)目中使用Mockito的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-10-10
Java使用正則表達(dá)式檢索、替換String中特定字符和正則表達(dá)式的一切
這篇文章主要給大家介紹了關(guān)于Java使用正則表達(dá)式檢索、替換String中特定字符和正則表達(dá)式的一切,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Java Web 登錄頁(yè)面的實(shí)現(xiàn)代碼實(shí)例
這篇文章主要介紹了Java Web 登錄頁(yè)面的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-03-03
springboot如何通過(guò)注解實(shí)現(xiàn)多線程
在Spring Boot中實(shí)現(xiàn)異步方法時(shí),如果直接在調(diào)用類(lèi)中使用`@Async`注解,可能會(huì)導(dǎo)致異步失敗,正確的做法是將實(shí)現(xiàn)異步的方法放在一個(gè)獨(dú)立的類(lèi)中,并通過(guò)Spring生成的bean來(lái)調(diào)用這個(gè)方法,這樣可以成功實(shí)現(xiàn)異步2024-12-12
Spring實(shí)現(xiàn)類(lèi)私有方法的幾個(gè)問(wèn)題(親測(cè)通用解決方案)
現(xiàn)實(shí)的業(yè)務(wù)場(chǎng)景中,可能需要對(duì)Spring的實(shí)現(xiàn)類(lèi)的私有方法進(jìn)行測(cè)試。本文給大家分享Spring實(shí)現(xiàn)類(lèi)私有方法面臨的幾個(gè)問(wèn)題及解決方案,感興趣的朋友跟隨小編一起看看吧2021-06-06
OpenFeign無(wú)法遠(yuǎn)程調(diào)用問(wèn)題及解決
文章介紹了在使用Feign客戶端時(shí)遇到的讀超時(shí)問(wèn)題,并分析了原因是系統(tǒng)啟動(dòng)時(shí)未先加載Nacos配置,為了解決這個(gè)問(wèn)題,建議將Nacos配置放在`bootstrap.yml`文件中,以便項(xiàng)目啟動(dòng)時(shí)優(yōu)先加載Nacos配置2024-11-11
Java開(kāi)發(fā)實(shí)現(xiàn)飛機(jī)大戰(zhàn)
這篇文章主要為大家詳細(xì)介紹了Java開(kāi)發(fā)實(shí)現(xiàn)飛機(jī)大戰(zhàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
淺談Java中Map和Set之間的關(guān)系(及Map.Entry)
這篇文章主要介紹了淺談Java中Map和Set之間的關(guān)系(及Map.Entry),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09

