教育行業(yè)A股IPO第一股(股票代碼 003032)

全國(guó)咨詢(xún)/投訴熱線(xiàn):400-618-4000

java培訓(xùn):ThreadPool用法與優(yōu)勢(shì)。

更新時(shí)間:2019年02月25日15時(shí)10分 來(lái)源:傳智播客java培訓(xùn) 瀏覽次數(shù):

  1. 線(xiàn)程池的優(yōu)點(diǎn):

  合理利用線(xiàn)程池能夠帶來(lái)三個(gè)好處。第一:降低資源消耗。通過(guò)重復(fù)利用已創(chuàng)建的線(xiàn)程降低線(xiàn)程創(chuàng)建和銷(xiāo)毀造成的消耗。第二:提高響應(yīng)速度。當(dāng)任務(wù)到達(dá)時(shí),任務(wù)可以不需要等到線(xiàn)程創(chuàng)建就能立即執(zhí)行。第三:提高線(xiàn)程的可管理性。線(xiàn)程是稀缺資源,如果無(wú)限制的創(chuàng)建,不僅會(huì)消耗系統(tǒng)資源,還會(huì)降低系統(tǒng)的穩(wěn)定性,使用線(xiàn)程池可以進(jìn)行統(tǒng)一的分配,調(diào)優(yōu)和監(jiān)控。但是要做到合理的利用線(xiàn)程池,必須對(duì)其原理了如指掌。

threadpool的用法優(yōu)勢(shì)

  2. 線(xiàn)程池框架Executor:

  java中的線(xiàn)程池是通過(guò)Executor框架實(shí)現(xiàn)的,ThreadPoolExecutor:線(xiàn)程池的具體實(shí)現(xiàn)類(lèi),一般用的各種線(xiàn)程池都是基于這個(gè)類(lèi)實(shí)現(xiàn)的。構(gòu)造方法如下:

  參數(shù)介紹:

  corePoolSize:線(xiàn)程池的核心線(xiàn)程數(shù),線(xiàn)程池中運(yùn)行的線(xiàn)程數(shù)永遠(yuǎn)不會(huì)超過(guò) corePoolSize 個(gè),默認(rèn)情況下可以一直存活。

  keepAliveTime: 默認(rèn)情況下,只有當(dāng)線(xiàn)程池中的線(xiàn)程數(shù)大于corePoolSize時(shí),keepAliveTime才會(huì)起作用,直到線(xiàn)程池中的線(xiàn)程數(shù)不大于corePoolSize,即當(dāng)線(xiàn)程池中的線(xiàn)程數(shù)大于corePoolSize時(shí),如果一個(gè)線(xiàn)程空閑的時(shí)間達(dá)到keepAliveTime,則會(huì)終止,直到線(xiàn)程池中的線(xiàn)程數(shù)不超過(guò)corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線(xiàn)程池中的線(xiàn)程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會(huì)起作用,直到線(xiàn)程池中的線(xiàn)程數(shù)為0;所以如果任務(wù)很多,并且每個(gè)任務(wù)執(zhí)行的時(shí)間比較短,可以調(diào)大這個(gè)時(shí)間,提高線(xiàn)程的利用率。

  maximumPoolSize:線(xiàn)程池允許的最大線(xiàn)程數(shù)。如果隊(duì)列滿(mǎn)了,并且已創(chuàng)建的線(xiàn)程數(shù)小于最大線(xiàn)程數(shù),則線(xiàn)程池會(huì)再創(chuàng)建新的線(xiàn)程執(zhí)行任務(wù)。值得注意的是如果使用了無(wú)界的任務(wù)隊(duì)列這個(gè)參數(shù)就沒(méi)什么效果。

  unit :表示 keepAliveTime 的單位;可選的單位有天,小時(shí),分鐘,毫秒。微秒,納秒等。

  workQueue:表示存放任務(wù)的阻塞隊(duì)列。

  BlockingQueue:阻塞隊(duì)列(BlockingQueue)是java.util.concurrent下的主要用來(lái)控制線(xiàn)程同步的工具。如果BlockQueue是空的,從BlockingQueue取東西的操作將會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue進(jìn)了東西才會(huì)被喚醒。同樣,如果BlockingQueue是滿(mǎn)的,任何試圖往里存東西的操作也會(huì)被阻斷進(jìn)入等待狀態(tài),直到BlockingQueue里有空間才會(huì)被喚醒繼續(xù)操作。

  阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場(chǎng)景,生產(chǎn)者是往隊(duì)列里添加元素的線(xiàn)程,消費(fèi)者是從隊(duì)列里拿元素的線(xiàn)程。阻塞隊(duì)列就是生產(chǎn)者存放元素的容器,而消費(fèi)者也只從容器里拿元素。具體的實(shí)現(xiàn)類(lèi)有LinkedBlockingQueue,ArrayBlockingQueued等。ArrayBlockingQueue:是一個(gè)基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列,此隊(duì)列按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序。LinkedBlockingQueue:一個(gè)基于鏈表結(jié)構(gòu)的阻塞隊(duì)列,此隊(duì)列按FIFO (先進(jìn)先出) 排序元素,吞吐量通常要高于ArrayBlockingQueue。synchronousQueue:這個(gè)隊(duì)列比較特殊,它不會(huì)保存提交的任務(wù),而是將直接新建一個(gè)線(xiàn)程來(lái)執(zhí)行新來(lái)的任務(wù)

  3. 線(xiàn)程池的線(xiàn)程程初始化

  默認(rèn)情況下,創(chuàng)建線(xiàn)程池之后,線(xiàn)程池中是沒(méi)有線(xiàn)程的,需要提交任務(wù)之后才會(huì)創(chuàng)建線(xiàn)程。在實(shí)際中如果需要線(xiàn)程池創(chuàng)建之后立即創(chuàng)建線(xiàn)程,可以通過(guò)以下兩個(gè)方法辦到:

  prestartCoreThread():初始化一個(gè)核心線(xiàn)程;

  prestartAllCoreThreads():初始化所有核心線(xiàn)程

  4. worker類(lèi)

  在ThreadPoolExecutor主要Worker類(lèi)來(lái)控制線(xiàn)程的復(fù)用。線(xiàn)程池創(chuàng)建線(xiàn)程時(shí),會(huì)將線(xiàn)程封裝成工作線(xiàn)程Worker,Worker在執(zhí)行完任務(wù)后,還會(huì)無(wú)限循環(huán)獲取工作隊(duì)列里的任務(wù)來(lái)執(zhí)行。

  5. 線(xiàn)程池的工作過(guò)程

  線(xiàn)程池剛創(chuàng)建時(shí),里面沒(méi)有一個(gè)線(xiàn)程。任務(wù)隊(duì)列是作為參數(shù)傳進(jìn)來(lái)的。不過(guò),就算隊(duì)列里面有任務(wù),線(xiàn)程池也不會(huì)馬上執(zhí)行它們。當(dāng)提交一個(gè)新任務(wù)到線(xiàn)程池時(shí),線(xiàn)程池會(huì)做如下判斷:

  如果正在運(yùn)行的線(xiàn)程數(shù)量小于 corePoolSize,那么馬上創(chuàng)建線(xiàn)程運(yùn)行這個(gè)任務(wù);

  如果正在運(yùn)行的線(xiàn)程數(shù)量大于或等于 corePoolSize,那么將這個(gè)任務(wù)放入隊(duì)列;

  如果這時(shí)候隊(duì)列滿(mǎn)了,而且正在運(yùn)行的線(xiàn)程數(shù)量小于 maximumPoolSize,那么還是要?jiǎng)?chuàng)建非核心線(xiàn)程立刻運(yùn)行這個(gè)任務(wù);

  如果隊(duì)列滿(mǎn)了,而且正在運(yùn)行的線(xiàn)程數(shù)量大于或等于 maximumPoolSize,那么會(huì)采取任務(wù)拒絕策略,如下:

  當(dāng)一個(gè)線(xiàn)程完成任務(wù)時(shí),它會(huì)從隊(duì)列中取下一個(gè)任務(wù)來(lái)執(zhí)行。

  當(dāng)一個(gè)線(xiàn)程無(wú)事可做,超過(guò)一定的時(shí)間(keepAliveTime)時(shí),線(xiàn)程池會(huì)判斷,如果當(dāng)前運(yùn)行的線(xiàn)程數(shù)大于corePoolSize,那么這個(gè)線(xiàn)程就被停掉。所以線(xiàn)程池的所有任務(wù)完成后,它最終會(huì)收縮到corePoolSize 的大小。

  6. 線(xiàn)程池的關(guān)閉

  ThreadPoolExecutor提供了兩個(gè)方法,用于線(xiàn)程池的關(guān)閉,分別是shutdown()和shutdownNow(),其中:shutdown():不會(huì)立即終止線(xiàn)程池,而是要等所有任務(wù)緩存隊(duì)列中的任務(wù)都執(zhí)行完后才終止,但再也不會(huì)接受新的任務(wù)。shutdownNow():立即終止線(xiàn)程池,并嘗試打斷正在執(zhí)行的任務(wù),并且清空任務(wù)緩存隊(duì)列,返回尚未執(zhí)行的任務(wù)。

  7. 線(xiàn)程池容量的動(dòng)態(tài)調(diào)整

  ThreadPoolExecutor提供了動(dòng)態(tài)調(diào)整線(xiàn)程池容量大小的方法:setCorePoolSize()和setMaximumPoolSize(),

  setCorePoolSize:設(shè)置核心池大小

  setMaximumPoolSize:設(shè)置線(xiàn)程池最大能創(chuàng)建的線(xiàn)程數(shù)目大小

  當(dāng)上述參數(shù)從小變大時(shí),ThreadPoolExecutor進(jìn)行線(xiàn)程賦值,還可能立即創(chuàng)建新的線(xiàn)程來(lái)執(zhí)行任務(wù)。

  8. 幾種類(lèi)型的線(xiàn)程池

  1) SingleThreadExecutor:?jiǎn)蝹€(gè)后臺(tái)線(xiàn)程 (其緩沖隊(duì)列是LinkedBlockingQueue,無(wú)界的)

  創(chuàng)建一個(gè)單線(xiàn)程的線(xiàn)程池。這個(gè)線(xiàn)程池只有一個(gè)核心線(xiàn)程在工作,也就是相當(dāng)于單線(xiàn)程串行執(zhí)行所有任務(wù)。如果這個(gè)唯一的線(xiàn)程因?yàn)楫惓=Y(jié)束,那么會(huì)有一個(gè)新的線(xiàn)程來(lái)替代它。此線(xiàn)程池保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。

  舉例子:比如一個(gè)村里只有一口井,每次只能一個(gè)人打水,先來(lái)先打。

  2) FixedThreadPool:只有核心線(xiàn)程的線(xiàn)程池,大小固定(其緩沖隊(duì)列是LinkedBlockingQueue,無(wú)界的) 。

  創(chuàng)建固定大小的線(xiàn)程池。每次提交一個(gè)任務(wù)就創(chuàng)建一個(gè)線(xiàn)程,直到線(xiàn)程達(dá)到線(xiàn)程池的最大大小。線(xiàn)程池的大小一旦達(dá)到最大值就會(huì)保持不變,如果某個(gè)線(xiàn)程因?yàn)閳?zhí)行異常而結(jié)束,那么線(xiàn)程池會(huì)補(bǔ)充一個(gè)新線(xiàn)程。

  舉例子:村里有3口井,大家排隊(duì)打井水,可以無(wú)數(shù)人排隊(duì),井只有3口,每次最多只能有3個(gè)人打井水。沒(méi)人打水時(shí),3口井也在那里。由于線(xiàn)程不會(huì)回收,F(xiàn)ixThreadPool會(huì)更快地響應(yīng)外界請(qǐng)求,這也很容易理解,就好像有人突然想打井水,井不是現(xiàn)用現(xiàn)建的。

  3) CachedThreadPool:無(wú)界線(xiàn)程池,可以進(jìn)行自動(dòng)線(xiàn)程回收。(其緩沖隊(duì)列是SynchronousQueue,一個(gè)是緩沖區(qū)為1的阻塞隊(duì)列

  如果線(xiàn)程池的大小超過(guò)了處理任務(wù)所需要的線(xiàn)程,那么就會(huì)回收部分空閑(60秒不執(zhí)行任務(wù))的線(xiàn)程,當(dāng)任務(wù)數(shù)增加時(shí),此線(xiàn)程池又可以智能的添加新線(xiàn)程來(lái)處理任務(wù)。此線(xiàn)程池不會(huì)對(duì)線(xiàn)程池大小做限制,線(xiàn)程池大小完全依賴(lài)于操作系統(tǒng)(或者說(shuō)JVM)能夠創(chuàng)建的最大線(xiàn)程大小。

  舉個(gè)例子:CachedThreadPool就像是一堆人去一個(gè)很大的咖啡館喝咖啡,里面服務(wù)員也很多,隨時(shí)去,隨時(shí)都可以喝到咖啡。但是為了響應(yīng)國(guó)家的“光盤(pán)行動(dòng)”,一個(gè)人喝剩下的咖啡會(huì)被保留60秒,供新來(lái)的客人使用,哈哈哈哈哈,好惡心啊。如果你運(yùn)氣好,沒(méi)有剩下的咖啡,你會(huì)得到一杯新咖啡。但是以前客人剩下的咖啡超過(guò)60秒,就變質(zhì)了,會(huì)被服務(wù)員回收掉。比較適合執(zhí)行大量的耗時(shí)較少的任務(wù)。喝咖啡人挺多的,喝的時(shí)間也不長(zhǎng)。

  4)ScheduledThreadPool:核心線(xiàn)程池固定,大小無(wú)限的線(xiàn)程池。核心線(xiàn)程數(shù)固定,非核心線(xiàn)程(閑著沒(méi)活干會(huì)被立即回收)數(shù)沒(méi)有限制。此線(xiàn)程池支持定時(shí)以及周期性執(zhí)行任務(wù)的需求。

0 分享到:
和我們?cè)诰€(xiàn)交談!