日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

10年架構(gòu)師經(jīng)驗(yàn)帶你詳細(xì)解析四種線程池

 

 線程池介紹:

使用線程池的好處有很多,比如節(jié)省系統(tǒng)資源的開銷,節(jié)省創(chuàng)建和銷毀線程的時(shí)間等,當(dāng)我們需要處理的任務(wù)較多時(shí),就可以使用線程池。

線程池是一種多線程處理形式,處理過(guò)程中將任務(wù)添加到隊(duì)列,然后在創(chuàng)建線程后自動(dòng)啟動(dòng)這些任務(wù)。線程池線程都是后臺(tái)線程。每個(gè)線程都使用默認(rèn)的堆棧大小,以默認(rèn)的優(yōu)先級(jí)運(yùn)行,并處于多線程單元中。如果某個(gè)線程在托管代碼中空閑(如正在等待某個(gè)事件),則線程池將插入另一個(gè)輔助線程來(lái)使所有處理器保持繁忙。如果所有線程池線程都始終保持繁忙,但隊(duì)列中包含掛起的工作,則線程池將在一段時(shí)間后創(chuàng)建另一個(gè)輔助線程但線程的數(shù)目永遠(yuǎn)不會(huì)超過(guò)最大值。超過(guò)最大值的線程可以排隊(duì),但他們要等到其他線程完成后才啟動(dòng)。

1.首先我們先看一下獲取四種線程池的代碼:

 ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);
 ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
 ExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
 ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

可以發(fā)現(xiàn)這四種線程池都是由Executors類生成的。依次點(diǎn)開四個(gè)方法的內(nèi)部實(shí)現(xiàn)發(fā)現(xiàn),它們最終調(diào)用的都是同一個(gè)ThreadPoolExecutor()的構(gòu)造器,而區(qū)別在于構(gòu)造器的參數(shù)不同。我們來(lái)看下ThreadPoolExecutor的參數(shù)列表:

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

正是由于這幾個(gè)參數(shù)的不同導(dǎo)致了四種線程池的工作機(jī)制不同。參考源碼對(duì)于參數(shù)的注釋,我們列出參數(shù)的含義。

  • corePoolSize:核心線程數(shù)量,常駐在線程池中的線程,即使它們是空閑的,也不會(huì)銷毀,除非設(shè)置allowCoreThreadTimeOut的值。
  • maximumPoolSize:線程池最大線程數(shù)量
  • keepAliveTime:超過(guò)核心數(shù)量的額外線程也就是非核心線程,在空閑指定的最大時(shí)間后被銷毀。(假設(shè)時(shí)間為5s,核心線程數(shù)為2,當(dāng)前線程為4,則超過(guò)核心線程數(shù)的其余兩個(gè)線程在空閑5秒后會(huì)被銷毀。)
  • unit:時(shí)間單位
  • workQueue:等待隊(duì)列
  • threadFactory:生成線程的工廠
  • handler:當(dāng)?shù)却?duì)列容量滿以及線程池?cái)?shù)量達(dá)到最大時(shí),如何處理新的任務(wù)。

AbortPolicy(默認(rèn)):直接拋出異常

CallerRunsPolicy:交給調(diào)用者所在線程執(zhí)行。(假設(shè)當(dāng)前調(diào)用者線程是Main,那么就交給Main處理)

DiscardOldestPolicy:丟棄最久未處理的任務(wù),再執(zhí)行當(dāng)前任務(wù)。(最久未處理的,在隊(duì)列中其實(shí)就是隊(duì)列頭節(jié)點(diǎn),查看源碼的確調(diào)用是poll()方法)

DiscardPolicy:丟掉該任務(wù),并且不拋異常。

線程池的工作機(jī)制:

當(dāng)持續(xù)往線程池添加任務(wù),

當(dāng)前線程數(shù)量小于核心線程數(shù)量的時(shí)候,新增線程。

當(dāng)前線程數(shù)量達(dá)到核心線程數(shù)量的時(shí)候,將任務(wù)放入等待隊(duì)列。

當(dāng)?shù)却?duì)列滿的時(shí)候,繼續(xù)創(chuàng)建新線程。

當(dāng)線程池?cái)?shù)量達(dá)到最大并且等待隊(duì)列也滿的時(shí)候,采取拒絕服務(wù)策略。

2.接下來(lái)我們就根據(jù)參數(shù)來(lái)分析不同的線程池:

FixedThreadPool

 public static ExecutorService newFixedThreadPool(int nThreads) {
 return new ThreadPoolExecutor(nThreads, nThreads,
 0L, TimeUnit.MILLISECONDS,
 new LinkedBlockingQueue<Runnable>());
 }

我們可以看到corePoolSize核心線程數(shù)量和maximumPoolSize最大線程數(shù)量是一致的,并且keepAliveTime為0。workQueue是LinkedBlockingQueue,這是一個(gè)鏈表阻塞隊(duì)列。可以得出結(jié)論:該線程池是一個(gè)固定數(shù)量的線程池,并且有一個(gè)無(wú)界的等待隊(duì)列。我們可以推導(dǎo)出該線程池適合處理任務(wù)量平穩(wěn)的場(chǎng)景。例如平均一秒接收10個(gè)任務(wù),接收任務(wù)量曲線不會(huì)很陡峭。

適合場(chǎng)景:適合少量的大任務(wù)(大任務(wù)處理慢,如果線程數(shù)量多的話,反而在切換線程上下文時(shí)損耗,所以控制線程在一定的數(shù)量)。

CachedThreadPool

public static ExecutorService newCachedThreadPool() {
 return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
 60L, TimeUnit.SECONDS,
 new SynchronousQueue<Runnable>());
 }

我們可以看到corePoolSize核心線程池為0,代表該線程沒(méi)有核心線程池,意味著線程都是可被回收銷毀的,線程池中有時(shí)會(huì)是空的。并且maximumPoolSize是int最大值,相當(dāng)于代表該線程池可以無(wú)限創(chuàng)建線程。keepAliveTime為60,代表空閑60秒回收線程。workQueue是SynchronousQueue,該同步隊(duì)列是一個(gè)沒(méi)有容量隊(duì)列,即一個(gè)任務(wù)到來(lái)后,要等待線程來(lái)消費(fèi),才能再繼續(xù)添加任務(wù)。我們推導(dǎo)出該線程池適合處理平時(shí)沒(méi)什么任務(wù)量,但有時(shí)任務(wù)量瞬間劇增的場(chǎng)景。

適合場(chǎng)景:大量的小任務(wù)(每個(gè)任務(wù)處理快,不會(huì)頻繁出現(xiàn)線程處理一半時(shí),切換其他線程)。

ScheduledThreadPool

public ScheduledThreadPoolExecutor(int corePoolSize) {
 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
 new DelayedWorkQueue());
 }

我們可以看到該線程池的corePoolSize核心線程數(shù)量和maximumPoolSize最大線程數(shù)量都是1,代表該線程有且只有一個(gè)固定的線程,既然是單線程,所以該線程池實(shí)現(xiàn)的是串行操作,沒(méi)有并發(fā)效果。workQueue是LinkedBlockingQueue,這是一個(gè)鏈表阻塞隊(duì)列。所以該線程池適合執(zhí)行串行執(zhí)行隊(duì)列中的任務(wù)。

適合場(chǎng)景:按順序串行處理的任務(wù)。

可能讀者會(huì)好奇keepAliveTime為0代表的含義? 是立即回收線程還是永不回收呢?

keepAliveTime參數(shù)注釋明確指明只對(duì)非核心線程有用。 我們可以從ScheduledThreadPool的源碼中推測(cè),如果0代表是永不回收的話,那么ScheduledThreadPool一旦創(chuàng)建出非核心線程的話就不會(huì)回收了?這樣是很不合理的。所以筆者認(rèn)為0代表立即回收。

public ScheduledThreadPoolExecutor(int corePoolSize) {
 super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
 new DelayedWorkQueue());
 }

此文章如有錯(cuò)誤懇請(qǐng)?jiān)u論指正。希望能通過(guò)這篇文章讓大家對(duì)線程池有更深的理解。

最后,需要關(guān)于分布式,微服務(wù),性能優(yōu)化,Spring,MyBatis,MySQL數(shù)據(jù)庫(kù)等等的源碼知識(shí)點(diǎn)請(qǐng)關(guān)注我哦!還有各種常見面試題詳解。(關(guān)注+轉(zhuǎn)發(fā),私信我“學(xué)習(xí)”,就可以領(lǐng)取架構(gòu)資料了哦!

我是小架,祝大家工作上能夠事業(yè)有成,學(xué)習(xí)上也可以打破瓶頸一路向上!

分享到:
標(biāo)簽:線程
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定