摘要:線程池為了節(jié)省系統(tǒng)在多線程并發(fā)時(shí)不斷創(chuàng)建和銷毀線程帶來的額外開銷,就需要引入線程池。其中表示一個(gè)線程池。表示一個(gè)線程工廠,通過可以取得一個(gè)特定功能的線程池。創(chuàng)建固定數(shù)目線程的線程池。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為。
【線程池
為了節(jié)省系統(tǒng)在多線程并發(fā)時(shí)不斷創(chuàng)建和銷毀線程帶來的額外開銷,就需要引入線程池。線程池的基本功能就是進(jìn)行線程的復(fù)用。當(dāng)系統(tǒng)接受一個(gè)提交的任務(wù)時(shí),并不會(huì)著急去創(chuàng)建一個(gè)新的線程去執(zhí)行這個(gè)任務(wù),而是去線程池中查詢是否有空閑的線程。
若有:直接使用這個(gè)線程。
若沒有:根據(jù)配置的策略執(zhí)行(有可能時(shí)創(chuàng)建一個(gè)新的線程,也有可能是阻塞該任務(wù)等待空閑線程)。待任務(wù)結(jié)束之后,也不會(huì)銷毀線程,而是放入線程池的空閑隊(duì)列,等待下次使用。
【executor框架為了能更好的控制多線程,jdk提供了一套executor框架。其中ThreadPoolExecutor表示一個(gè)線程池。Executors表示一個(gè)線程工廠,通過Executors可以取得一個(gè)特定功能的線程池。
public static ExecutorService newFixedThreadPool(int nThreads)
創(chuàng)建固定數(shù)目線程的線程池。
public static ExecutorService newCachedThreadPool()
創(chuàng)建一個(gè)可緩存的線程池,調(diào)用execute 將重用以前構(gòu)造的線程(如果線程可用)。如果現(xiàn)有線程沒有可用的,則創(chuàng)建一個(gè)新線程并添加到池中。終止并從緩存中移除那些已有 60 秒鐘未被使用的線程。
public static ExecutorService newSingleThreadExecutor()
創(chuàng)建一個(gè)單線程化的Executor。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
創(chuàng)建一個(gè)支持定時(shí)及周期性的任務(wù)執(zhí)行的線程池,多數(shù)情況下可用來替代Timer類。
但是這些工廠方法最后都是使用的ThreadPoolExecutor這個(gè)類。
【ThreadPoolExecutor參數(shù)含義- corePoolSize:核心池的大小,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用prestartAllCoreThreads()或者prestartCoreThread()方法。從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0。當(dāng)有任務(wù)來之后,就會(huì)創(chuàng)建一個(gè)線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達(dá)到corePoolSize后,就會(huì)把到達(dá)的任務(wù)放到緩存隊(duì)列當(dāng)中; - maximumPoolSize:線程池最大線程數(shù),這個(gè)參數(shù)也是一個(gè)非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個(gè)線程; - keepAliveTime:表示線程沒有任務(wù)執(zhí)行時(shí)最多保持多久時(shí)間會(huì)終止。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),keepAliveTime才會(huì)起作用。直到線程池中的線程數(shù)不大于corePoolSize,即當(dāng)線程池中的線程數(shù)大于corePoolSize時(shí),如果一個(gè)線程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止,直到線程池中的線程數(shù)不超過corePoolSize。 但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會(huì)起作用,直到線程池中的線程數(shù)為0; - unit:參數(shù)keepAliveTime的時(shí)間單位 - workQueue:一個(gè)阻塞隊(duì)列,用來存儲(chǔ)等待執(zhí)行的任務(wù),這個(gè)參數(shù)的選擇也很重要,會(huì)對(duì)線程池的運(yùn)行過程產(chǎn)生重大影響,一般來說,這里的阻塞隊(duì)列有以下幾種選擇: ArrayBlockingQueue;LinkedBlockingQueue;SynchronousQueue; - threadFactory:線程工廠,主要用來創(chuàng)建線程; - handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略,有以下四種取值: - ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出 RejectedExecutionException異常。 - ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。 - ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程) - ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)【現(xiàn)在重點(diǎn)講講workQueue
參數(shù)workQueue是指被提交但未執(zhí)行的任務(wù)隊(duì)列,他是一個(gè)BlockingQueue接口的對(duì)象,僅用于存放runnable對(duì)象。根據(jù)隊(duì)列功能分類,在ThreadPoolExecutor構(gòu)造參數(shù)中可以使用以下幾種BlockingQueue:
- 直接提交隊(duì)列:SynchronousQueue對(duì)象提供。SynchronousQueue是一個(gè)特殊的BlockingQueue,SynchronousQueue沒有容量,不保存任務(wù)他總是將任務(wù)提交給線程執(zhí)行,如果沒有空閑的線程就會(huì)嘗試創(chuàng)建新的線程。如果線程數(shù)達(dá)到maximumPoolSize,則執(zhí)行拒絕策略。因此使用SynchronousQueue通常會(huì)設(shè)置很大的maximumPoolSize,否則容易執(zhí)行拒絕策略。 - 有界任務(wù)隊(duì)列:有界任務(wù)隊(duì)列可以使用ArrayBlockingQueue實(shí)現(xiàn),其構(gòu)造函數(shù)必須帶一個(gè)參數(shù)表示最大容量。當(dāng)使用有界任務(wù)隊(duì)列的時(shí)候:如果有新任務(wù)提交,若線程數(shù)小于corePoolSize,則會(huì)優(yōu)先創(chuàng)建新的線程,若大于corePoolSize則會(huì)將任務(wù)置于等待隊(duì)列中,如果等待隊(duì)列已滿,在線程數(shù)小于maximumPoolSize時(shí),會(huì)創(chuàng)建新的線程執(zhí)行任務(wù),否則執(zhí)行拒絕策略。最終,除非系統(tǒng)非常繁忙,否則線程數(shù)將會(huì)維持在corePoolSize。 - 無界任務(wù)隊(duì)列:無界任務(wù)隊(duì)列可以通過LinkedBlockingQueue類實(shí)現(xiàn)。與有界隊(duì)列相比,除非系統(tǒng)資源耗盡,否則無界任務(wù)隊(duì)列不存在任務(wù)入隊(duì)失敗的情況。當(dāng)有新任務(wù)提交的時(shí)候:如果系統(tǒng)線程小于corePoolSize,會(huì)創(chuàng)建新的線程執(zhí)行任務(wù),如果大于corePoolSize則不會(huì)增加新的線程,任務(wù)會(huì)進(jìn)入等待隊(duì)列,無界隊(duì)列會(huì)持續(xù)增長,直到系統(tǒng)資源耗盡。 - 優(yōu)先任務(wù)隊(duì)列:帶有執(zhí)行優(yōu)先級(jí)的隊(duì)列,通過PriorityBlockingQueue實(shí)現(xiàn),可以控制任務(wù)執(zhí)行順序特殊的無界隊(duì)列。無論有界還是無界隊(duì)列,都是fifo的執(zhí)行任務(wù),但是優(yōu)先級(jí)任務(wù)隊(duì)列可以根據(jù)任務(wù)自身的優(yōu)先級(jí)決定任務(wù)執(zhí)行順序,在確保了性能的同時(shí),也能保證執(zhí)行質(zhì)量(高優(yōu)先級(jí)任務(wù)先執(zhí)行)。【線程池如何復(fù)用線程
我們知道線程池會(huì)復(fù)用線程,但是它的內(nèi)部邏輯是如何將一個(gè)Runnable對(duì)象賦值給Thread的呢?
1.線程池內(nèi)部維護(hù)的不是Thread對(duì)象而是一個(gè)內(nèi)部類Worker:
它繼承了AbstractQueuedSynchronizer類,實(shí)現(xiàn)了一個(gè)非重入的鎖。該鎖會(huì)保護(hù)一個(gè)正在等待任務(wù)被執(zhí)行的Worker不被interrupt操作打斷。為什么不用ReentrantLock,要用非重入的鎖?因?yàn)樽髡卟幌胱屵@個(gè)Worker task在setCorePoolSize這種線程池控制方法調(diào)用時(shí)能重新獲取到鎖。當(dāng)提交一個(gè)任務(wù)時(shí),如果需要?jiǎng)?chuàng)建一個(gè)線程(何時(shí)需要在下一節(jié)中探討)時(shí),就調(diào)用線程工廠創(chuàng)建一個(gè)線程,同時(shí)將線程綁定到Worker工作隊(duì)列中。需要說明的是,Worker隊(duì)列構(gòu)造的時(shí)候帶著一個(gè)任務(wù)Runnable,因此Worker創(chuàng)建時(shí)總是綁定著一個(gè)待執(zhí)行任務(wù)。換句話說,創(chuàng)建線程的前提是有必要?jiǎng)?chuàng)建線程,不會(huì)無緣無故創(chuàng)建一堆空閑線程等著任務(wù)。這是節(jié)省資源的一種方式。
2.線程重用:線程重用的核心是,它把Thread.start()給屏蔽起來了(一定不要重復(fù)調(diào)用),然后它自己有一個(gè)Runnable.run(),循環(huán)在跑,跑的過程中不斷檢查我們是否有新加入的子Runnable對(duì)象,有就調(diào)一下我們的run(),其實(shí)就一個(gè)大run()把其它小run()#1,run()#2,...給串聯(lián)起來了,基本原理就這么簡單。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/68072.html
摘要:死亡狀態(tài)線程退出有可能是正常執(zhí)行完成也有可能遇見異常退出。類有新建與死亡狀態(tài)返回其余狀態(tài)返回判斷線程是否存活。線程因某些原因進(jìn)入阻塞狀態(tài)。執(zhí)行同步代碼塊的過程中執(zhí)行了當(dāng)前線程放棄開始睡眠進(jìn)入就緒狀態(tài)但是不會(huì)釋放鎖。 【java內(nèi)存模型簡介 JVM中存在一個(gè)主存區(qū)(Main Memory或Java Heap Memory),Java中所有變量都是存在主存中的,對(duì)于所有線程進(jìn)行共享,而每個(gè)...
摘要:在這個(gè)范圍廣大的并發(fā)技術(shù)領(lǐng)域當(dāng)中多線程編程可以說是基礎(chǔ)和核心,大多數(shù)抽象并發(fā)問題的構(gòu)思與解決都是基于多線程模型來進(jìn)行的。一般來說,多線程程序會(huì)面臨三類問題正確性問題效率問題死鎖問題。 多線程編程或者說范圍更大的并發(fā)編程是一種非常復(fù)雜且容易出錯(cuò)的編程方式,但是我們?yōu)槭裁催€要冒著風(fēng)險(xiǎn)艱辛地學(xué)習(xí)各種多線程編程技術(shù)、解決各種并發(fā)問題呢? 因?yàn)椴l(fā)是整個(gè)分布式集群的基礎(chǔ),通過分布式集群不僅可以大...
摘要:一個(gè)線程池包含很多準(zhǔn)備運(yùn)行的空閑線程,每當(dāng)執(zhí)行完畢后,線程不會(huì)死亡而是回到線程池準(zhǔn)備為下一個(gè)請(qǐng)求提供服務(wù)。另一個(gè)使用線程池的理由是減少并發(fā)線程數(shù)。創(chuàng)建大量線程會(huì)大大降低性能甚至拖垮虛擬機(jī)。 【Future的概念 interface Future ,表示異步計(jì)算的結(jié)果,F(xiàn)uture有個(gè)get方法而獲取結(jié)果只有在計(jì)算完成時(shí)獲取,否則會(huì)一直阻塞直到任務(wù)轉(zhuǎn)入完成狀態(tài),然后會(huì)返回結(jié)果或者拋出異常...
摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)??梢娝氖褂茫陂_始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...
摘要:表示的是兩個(gè),當(dāng)其中任意一個(gè)計(jì)算完并發(fā)編程之是線程安全并且高效的,在并發(fā)編程中經(jīng)常可見它的使用,在開始分析它的高并發(fā)實(shí)現(xiàn)機(jī)制前,先講講廢話,看看它是如何被引入的。電商秒殺和搶購,是兩個(gè)比較典型的互聯(lián)網(wǎng)高并發(fā)場景。 干貨:深度剖析分布式搜索引擎設(shè)計(jì) 分布式,高可用,和機(jī)器學(xué)習(xí)一樣,最近幾年被提及得最多的名詞,聽名字多牛逼,來,我們一步一步來擊破前兩個(gè)名詞,今天我們首先來說說分布式。 探究...
閱讀 3737·2021-11-24 10:23
閱讀 2780·2021-09-06 15:02
閱讀 1284·2021-08-23 09:43
閱讀 2361·2019-08-30 15:44
閱讀 3058·2019-08-30 13:18
閱讀 794·2019-08-23 16:56
閱讀 1753·2019-08-23 16:10
閱讀 550·2019-08-23 15:08