前言
成都創(chuàng)新互聯(lián)公司是一家專業(yè)從事網(wǎng)站設(shè)計、做網(wǎng)站、網(wǎng)頁設(shè)計的品牌網(wǎng)絡(luò)公司。如今是成都地區(qū)具影響力的網(wǎng)站設(shè)計公司,作為專業(yè)的成都網(wǎng)站建設(shè)公司,成都創(chuàng)新互聯(lián)公司依托強大的技術(shù)實力、以及多年的網(wǎng)站運營經(jīng)驗,為您提供專業(yè)的成都網(wǎng)站建設(shè)、營銷型網(wǎng)站建設(shè)及網(wǎng)站設(shè)計開發(fā)服務(wù)!線程池是一個很重要概念,在初學(xué)時我們都是通過new Thread來開啟一個線程進行聯(lián)網(wǎng)操作,但是跟服務(wù)端交互多了,如果還是使用new Thread()來開啟子線程,在一個應(yīng)用中我們頻繁的去通過這個方法去開啟線程,這對性能來說是很大的浪費,頻繁的開啟銷毀線程對內(nèi)存的消耗是很大的,而頻繁的開啟線程也讓整個應(yīng)用的線程管理顯得很混亂,這是不可取的,這時候使用線程池就可以解決這些問題了,這篇文章我會嘗試將線程池概念和應(yīng)用說清楚。
1.線程的運行機制
開啟線程過多,會消耗cpu
單核cpu,同一時刻只能處理一個線程,多核cpu同一時刻可以處理多個線程
操作系統(tǒng)為每個運行線程安排一定的CPU時間—-
時間片
,系統(tǒng)通過一種循環(huán)的方式為線程提供時間片,線程在自己的時間內(nèi)運行,因為時間相當(dāng)短,多個線程頻繁地發(fā)生切換,因此給用戶的感覺就是好像多個線程同時運行一樣,但是如果計算機有多個CPU,線程就能真正意義上的同時運行了.
線程池是預(yù)先創(chuàng)建線程的一種技術(shù)。線程池在還沒有任務(wù)到來之前,創(chuàng)建一定數(shù)量的線程,放入空閑隊列中,然后對這些資源進行復(fù)用。
減少頻繁的創(chuàng)建和銷毀對象。
頻繁創(chuàng)建和銷毀線程耗資源,耗時間
因為有的線程執(zhí)行時間比創(chuàng)建和銷毀一個線程的時間還長`
Executor:Java里面線程池的頂級接口
ExecutorService:真正的線程池接口
ScheduledExecutorService:能和Timer/TimerTask類似,解決那些需要任務(wù)重復(fù)執(zhí)行的問題
ThreadPoolExecutor(重點):ExecutorService的默認(rèn)實現(xiàn)。
ScheduledThreadPoolExecutor:繼承ThreadPoolExecutor的ScheduledExecutorService接口實現(xiàn),周期性任務(wù)調(diào)度的類實現(xiàn)。
Executors:可以一行代碼創(chuàng)建一些常見的線程池。
Executors:jdk1.5之后的一個新類,
提供了一些靜態(tài)工廠,生成一些常用的線程池
,ThreadPoolExecutor是Executors類的底層實現(xiàn)
1.newSingleThreadExecutor
創(chuàng)建一個單線程的線程池。這個線程池只有一個線程在工作,也就是相當(dāng)于單線程串行執(zhí)行>所有任務(wù)。如果這個唯一的線程因為異常結(jié)束,那么會有一個新的線程來替代它。此線程池>保證所有任務(wù)的執(zhí)行順序按照任務(wù)的提交順序執(zhí)行。
2.newFixedThreadPool
創(chuàng)建固定大小的線程池。每次提交一個任務(wù)就創(chuàng)建一個線程,直到線程達到線程池的大大小。線程池的大小一旦達到大值就會保持不變,如果某個線程因為執(zhí)行異常而結(jié)束,那么線程池會補充一個新線程。
3.newCachedThreadPool
創(chuàng)建一個可緩存的線程池。如果線程池的大小超過了處理任務(wù)所需要的線程,
那么就會回收部分空閑(60秒不執(zhí)行任務(wù))的線程,當(dāng)任務(wù)數(shù)增加時,此線程池又可以智能的添加新線程來處理任務(wù)。此線程池不會對線程池大小做限制,線程池大小完全依賴于操作系統(tǒng)(或者說JVM)能夠創(chuàng)建的大線程大小。
4.newScheduledThreadPool
創(chuàng)建一個大小無限的線程池。此線程池支持定時以及周期性執(zhí)行任務(wù)的需求。
//構(gòu)造方法
public ThreadPoolExecutor(int corePoolSize,//核心池的大小
int maximumPoolSize,//線程池大線程數(shù)
long keepAliveTime,//保持時間
TimeUnit unit,//時間單位
BlockingQueueworkQueue,//任務(wù)隊列
ThreadFactory threadFactory,//線程工廠
RejectedExecutionHandler handler) //異常的捕捉器
corePoolSize:核心池的大小
,這個參數(shù)跟后面講述的線程池的實現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒有任何線程,而是等待有任務(wù)到來才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒有任務(wù)到來之前就創(chuàng)建corePoolSize個線程或者一個線程。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當(dāng)有任務(wù)來之后,就會創(chuàng)建一個線程去執(zhí)行任務(wù),當(dāng)線程池中的線程數(shù)目達到corePoolSize后,就會把到達的任務(wù)放到緩存隊列當(dāng)中;
maximumPoolSize:線程池大線程數(shù)
,這個參數(shù)也是一個非常重要的參數(shù),它表示在線程池中最多能創(chuàng)建多少個線程;
keepAliveTime:表示線程沒有任務(wù)執(zhí)行時最多保持多久時間會終止
。默認(rèn)情況下,只有當(dāng)線程池中的線程數(shù)大于corePoolSize時,keepAliveTime才會起作用,直到線程池中的線程數(shù)不大于corePoolSize,即當(dāng)線程池中的線程數(shù)大于corePoolSize時,如果一個線程空閑的時間達到keepAliveTime,則會終止,直到線程池中的線程數(shù)不超過corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時,keepAliveTime參數(shù)也會起作用,直到線程池中的線程數(shù)為0;
unit:參數(shù)keepAliveTime的時間單位
,有7種取值
TimeUnit.DAYS; //天 TimeUnit.HOURS; //小時 TimeUnit.MINUTES; //分鐘 TimeUnit.SECONDS; //秒 TimeUnit.MILLISECONDS; //毫秒 TimeUnit.MICROSECONDS; //微妙 TimeUnit.NANOSECONDS; //納秒
workQueue : 任務(wù)隊列
,是一個阻塞隊列,用來存儲等待執(zhí)行的任務(wù),這個參數(shù)的選擇也很重要,會對線程池的運行過程產(chǎn)生重大影響,參考BlockingQueue
ArrayBlockingQueue; LinkedBlockingQueue; SynchronousQueue;
threadFactory : 線程工廠
,如何去創(chuàng)建線程的
handler : 任務(wù)隊列添加異常的捕捉器
,參考 RejectedExecutionHandler
ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常
ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
isShutdown() : 判斷線程池是否關(guān)閉
isTerminated() : 判斷線程池中任務(wù)是否執(zhí)行完成
shutdown() : 調(diào)用后不再接收新任務(wù),如果里面有任務(wù),就執(zhí)行完
shutdownNow() : 調(diào)用后不再接受新任務(wù),如果有等待任務(wù),移出隊列;有正在執(zhí)行的,嘗試停止之
submit() : 提交執(zhí)行任務(wù)
execute() : 執(zhí)行任務(wù)
如果當(dāng)前線程池中的線程數(shù)目小于corePoolSize,則每來一個任務(wù),就會創(chuàng)建執(zhí)行這個任務(wù);
如果當(dāng)前線程池中的線程數(shù)目>=corePoolSize,則每來一個任務(wù),會嘗試將其添加到任務(wù)緩存隊列當(dāng)中
若添加成功,則該任務(wù)會等待空閑線程將其取出去執(zhí)行;
若添加失敗(一般來說是任務(wù)緩存隊列已滿),則會嘗試創(chuàng)建新的線程去執(zhí)行這個任務(wù);
如果當(dāng)前線程池中的線程數(shù)目達到maximumPoolSize,則會采取任務(wù)拒絕策略進行處理;
如果線程池中的線程數(shù)量大于 corePoolSize時,如果某線程空閑時間超過keepAliveTime,線程將被終止,直至線程池中的線程數(shù)目不大于corePoolSize;如果允許為核心池中的線程設(shè)置存活時間,那么核心池中的線程空閑時間超過keepAliveTime,線程也會被終止。
假如有一個工廠,工廠里面有10(
corePoolSize
)個工人,每個工人同時只能做一件任務(wù)。因此只要當(dāng)10個工人中有工人是空閑的,
來了任務(wù)就分配
給空閑的工人做;當(dāng)10個工人都有任務(wù)在做時,如果還來了任務(wù),就把任務(wù)進行排隊等待(
任務(wù)隊列
);如果說新任務(wù)數(shù)目增長的速度遠遠大于工人做任務(wù)的速度,那么此時工廠主管可能會想補救措施,比如重新招4個臨時工人(
創(chuàng)建新線程
)進來;然后就將任務(wù)也分配給這4個臨時工人做;如果說著14個工人做任務(wù)的速度還是不夠,此時工廠主管可能就要考慮不再接收新的任務(wù)或者拋棄前面的一些任務(wù)了(
拒絕執(zhí)行
)。當(dāng)這14個工人當(dāng)中有人空閑時,而且空閑超過一定時間(
空閑時間
),新任務(wù)增長的速度又比較緩慢,工廠主管可能就考慮辭掉4個臨時工了,只保持原來的10個工人,畢竟請額外的工人是要花錢的
阻塞隊列,如果BlockingQueue是空的,從BlockingQueue取東西的操作將會被阻斷進入等待狀態(tài),直到BlockingQueue進了東西才會被喚醒,同樣,如果BlockingQueue是滿的,任何試圖往里存東西的操作也會被阻斷進入等待狀態(tài),直到BlockingQueue里有空間時才會被喚醒繼續(xù)操作。
基礎(chǔ)API介紹
往隊列中加元素的方法
從隊列中取元素的方法
add(E) : 非阻塞方法, 把元素加到BlockingQueue里,如果BlockingQueue可以容納,則返回true,否則拋出異常。
offer(E) : 非阻塞, 表示如果可能的話,將元素加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則返回false。
put(E):阻塞方法, 把元素加到BlockingQueue里,如果BlockingQueue沒有空間,則調(diào)用此方法的線程被阻斷直到BlockingQueue里有空間再繼續(xù)。
poll(time): 阻塞方法,取走BlockingQueue里排在首位的元素,若不能立即取出,則可以等time參數(shù)規(guī)定的時間,取不到時返回null。
take():取走BlockingQueue里排在首位的對象,若BlockingQueue為空,阻斷進入等待狀態(tài)直到BlockingQueue有新的對象被加入為止。
ArrayBlockingQueue(有界隊列)
: FIFO 隊列,規(guī)定大小的BlockingQueue,其構(gòu)造函數(shù)必須帶一個int參數(shù)來指明其大小
LinkedBlockingQueue(×××隊列)
:FIFO 隊列,大小不定的BlockingQueue,若其構(gòu)造函數(shù)帶一個規(guī)定大小的參數(shù),生成的BlockingQueue有大小限制,若不帶大小參數(shù),所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定。
PriorityBlockingQueue
:優(yōu)先級隊列, 類似于LinkedBlockingQueue,但隊列中元素非 FIFO, 依據(jù)對象的自然排序順序或者是構(gòu)造函數(shù)所帶的Comparator決定的順序
SynchronousQueue(直接提交策略)
: 交替隊列,隊列中操作時必須是先放進去,接著取出來,交替著去處理元素的添加和移除
ThreadPoolExecutor.AbortPolicy
當(dāng)添加任務(wù)出錯時的策略捕獲器,如果出現(xiàn)錯誤,則直接拋出異常
ThreadPoolExecutor.CallerRunsPolicy
當(dāng)添加任務(wù)出錯時的策略捕獲器,如果出現(xiàn)錯誤,直接執(zhí)行加入的任務(wù)
ThreadPoolExecutor.DiscardOldestPolicy
當(dāng)添加任務(wù)出錯時的策略捕獲器,如果出現(xiàn)錯誤,移除第一個任務(wù),執(zhí)行加入的任務(wù)
ThreadPoolExecutor.DiscardPolicy
當(dāng)添加任務(wù)出錯時的策略捕獲器,如果出現(xiàn)錯誤,不做處理
看完本文有收獲?請分享給更多人
Android 干貨
歡迎關(guān)注我們,掃描和長按下方的二維碼可快速關(guān)注我們。或搜索微信眾號:AndroidNiubility。
公眾號:AndroidNiubility
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。