1韧拒、為什么JDK1.5引入線程池
在Java中伞租,如果每個任務(wù)都創(chuàng)建一個新的thread贞谓,開銷是非常大的。除了創(chuàng)建和銷毀線程的時間開銷外葵诈,還消耗大量的系統(tǒng)資源裸弦。為了規(guī)避以上問題,盡可能減少創(chuàng)建和銷毀線程的次數(shù)作喘,特別是一些資源耗費比較大的線程的創(chuàng)建和銷毀理疙,盡量利用已有的線程對象來進(jìn)行服務(wù),這就是線程池引入的原因泞坦。?
2窖贤、ThreadPoolExecutor類分析
(a)ThreadPoolExecutor構(gòu)造函數(shù):
public ThreadPoolExecutor(int corePoolSize,
? int maximumPoolSize,
? long keepAliveTime,
? TimeUnit unit,
? BlockingQueue<Runnable> workQueue,
? ThreadFactory threadFactory,
? RejectedExecutionHandler handler);
1)corePoolSize 核心線程數(shù)?
(2)maximumPoolSize 最大線程數(shù)
(3)keepAliveTime 線程被回收前的空閑時間
(4)workQueue 任務(wù)隊列
(5)threadFactory 線程創(chuàng)建工廠
(6)handler 線程池對拒絕任務(wù)的處理策略
(b)ThreadPoolExecutor運行原理:
ThreadPoolExecutor將根據(jù)corePoolSize和maximumPoolSize設(shè)置的值調(diào)整線程池大小。當(dāng)新任務(wù)調(diào)用方法execute(Runnable)提交時,如果運行的線程少于corePoolSize赃梧,則創(chuàng)建新線程來處理請求滤蝠。如果正在運行的線程數(shù)等于corePoolSize時,則新任務(wù)被添加到隊列中授嘀,直到隊列滿物咳。當(dāng)隊列滿了后,會繼續(xù)開辟新線程來處理任務(wù)蹄皱,但不超過最大線程數(shù)览闰。當(dāng)任務(wù)隊列滿了并且已開辟了最大線程數(shù),此時又來了新任務(wù)巷折,ThreadPoolExecutor會拒絕服務(wù)压鉴。
(c)keepAliveTime注意事項:
/**
* Timeout in nanoseconds for idle threads waiting for work.
* Threads use this timeout when there are more than corePoolSize
* present or if allowCoreThreadTimeOut. Otherwise they wait
* forever for new work.
*/
private volatile long keepAliveTime;
說明:當(dāng)線程空閑超過keepAliveTime,非核心線程會被回收盔几,若allowCoreThreadTimeOut為true則核心線程也會被回收晴弃。
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
private volatile boolean allowCoreThreadTimeOut;
說明:默認(rèn)情況下,核心線程不會被回收逊拍;當(dāng)allowCoreThreadTimeOut為true上鞠,核心線程也會被回收。
3芯丧、任務(wù)隊列
BlockingQueue<Runnable> workQueue;
workQueue是一個BlockingQueue接口的對象芍阎,僅用于存放Runnable對象。
(1)直接提交(如SynchronousQueue)
直接提交策略表示線程池不對任務(wù)進(jìn)行緩存缨恒。新進(jìn)任務(wù)直接提交給線程池谴咸,當(dāng)線程池中沒有空閑線程時,創(chuàng)建一個新的線程處理此任務(wù)骗露。這種策略需要線程池具有無限增長的可能性岭佳。
Executors.newCachedThreadPool()使用SynchronousQueue創(chuàng)建線程池。
(2)無界隊列(如不具有預(yù)定義容量的LinkedBlockingQueue)
LinkedBlockingQueue將導(dǎo)致當(dāng)所有 corePoolSize 線程都忙時新任務(wù)在隊列中等待萧锉。這樣珊随,創(chuàng)建的線程就不會超過 corePoolSize。(因此柿隙,maximumPoolSize 的值也就無效了叶洞。)當(dāng)每個任務(wù)完全獨立于其他任務(wù),即任務(wù)執(zhí)行互不影響時禀崖,適合于使用無界隊列衩辟。
Executors.newFixedThreadPool(3)使用LinkedBlockingQueue創(chuàng)建線程池。
Executors.newSingleThreadExecutor()使用LinkedBlockingQueue創(chuàng)建線程池波附。
(3)有界隊列(如ArrayBlockingQueue)
有界隊列(如ArrayBlockingQueue)有助于防止資源耗盡當(dāng)最大線程數(shù)有限時艺晴,但是可能較難調(diào)整和控制昼钻。隊列大小和最大池大小可能需要相互折衷。
(4)優(yōu)先級隊列(如PriorityBlockingQueue)
(5)DelayedWorkQueue
DelayedWorkQueue是ScheduledThreadPoolExecutor的靜態(tài)內(nèi)部類财饥。
Executors.newScheduledThreadPool(3)使用DelayedWorkQueue創(chuàng)建線程池换吧。
4、拒絕策略
接口RejectedExecutionHandler提供了拒絕任務(wù)處理的自定義方法的機(jī)會钥星。在ThreadPoolExecutor中已經(jīng)包含四種拒絕策略沾瓦。
(1)AbortPolicy
拒絕策略:拋出運行時異常RejectedExecutionException。
這種策略丟棄任務(wù)谦炒,并拋出異常贯莺。(jdk默認(rèn)策略)
(2)DiscardPolicy
拒絕策略:不能執(zhí)行的任務(wù)將被丟棄。
這種策略什么都沒做宁改。
(3)DiscardOldestPolicy
拒絕策略:如果執(zhí)行程序尚未關(guān)閉缕探,則位于工作隊列頭部的任務(wù)將被刪除,然后重試執(zhí)行程序还蹲。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
? ? if (!e.isShutdown()) {
? ? ? ? e.getQueue().poll();
? ? ? ? e.execute(r);
? ? }
}
該策略稍微復(fù)雜一些爹耗,在pool沒有關(guān)閉的前提下首先丟掉緩存在隊列中的最早的任務(wù),然后重新嘗試運行該任務(wù)谜喊。
(4)CallerRunsPolicy
拒絕策略:線程調(diào)用運行該任務(wù)的 execute 本身潭兽。此策略提供簡單的反饋控制機(jī)制,能夠減緩新任務(wù)的提交速度斗遏。
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
? ? if (!e.isShutdown()) {
? ? ? ? r.run();
? ? }
}
這個策略不想放棄執(zhí)行任務(wù)山卦。但是由于池中已經(jīng)沒有任何資源了,那么就直接使用調(diào)用該execute的線程本身來執(zhí)行诵次。