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

全國(guó)咨詢/投訴熱線:400-618-4000

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

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

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

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

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

  2. 線程池框架Executor:

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

  參數(shù)介紹:

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

  keepAliveTime: 默認(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;所以如果任務(wù)很多,并且每個(gè)任務(wù)執(zhí)行的時(shí)間比較短,可以調(diào)大這個(gè)時(shí)間,提高線程的利用率。

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

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

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

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

  阻塞隊(duì)列常用于生產(chǎn)者和消費(fèi)者的場(chǎng)景,生產(chǎn)者是往隊(duì)列里添加元素的線程,消費(fèi)者是從隊(duì)列里拿元素的線程。阻塞隊(duì)列就是生產(chǎn)者存放元素的容器,而消費(fèi)者也只從容器里拿元素。具體的實(shí)現(xiàn)類有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è)線程來執(zhí)行新來的任務(wù)

  3. 線程池的線程程初始化

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

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

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

  4. worker類

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

  5. 線程池的工作過程

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  8. 幾種類型的線程池

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

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

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

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

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

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

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

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

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

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

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