五種線程池,四種拒絕策略,三種阻塞隊(duì)列

線程池的工作原理:
ThreadPoolExecutor(int corePoolSize,// 核心線程數(shù)
int maximumPoolSize,//最大線程數(shù)
long keepAliveTime,//空閑線程存活時(shí)間
TimeUnit unit,//存活時(shí)間單位
BlockingQueue workQueue,//阻塞隊(duì)列
RejectedExecutionHandler handler)//拒絕策略
當(dāng)ThreadPoolExecutor線程池被創(chuàng)建的時(shí)候,里邊是沒(méi)有工作線程的,直到有任務(wù)進(jìn)來(lái)(執(zhí)行了execute方法)才開(kāi)始創(chuàng)建線程去工作,工作原理如下(即execute方法運(yùn)行原理):
調(diào)用線程池的execute方法的時(shí)候如果當(dāng)前的工作線程數(shù) 小于 核心線程數(shù),則創(chuàng)建新的線程執(zhí)行任務(wù);否則將任務(wù)加入阻塞隊(duì)列。如果隊(duì)列滿了則根據(jù)最大線程數(shù)去創(chuàng)建額外(核心線程數(shù)以外)的工作線程去執(zhí)行任務(wù);如果工作線程數(shù)達(dá)到了最大線程數(shù),則根據(jù)拒絕策略去執(zhí)行。存活時(shí)間到期的話只是回收核心線程(maximumPoolSize - corePoolSize)以外的線程
// 分3個(gè)步驟進(jìn)行:
// 1. 如果運(yùn)行的線程少于corePoolSize,請(qǐng)嘗試使用給定的命令作為第一個(gè)線程啟動(dòng)一個(gè)新線程的任務(wù)。對(duì)addWorker的調(diào)用會(huì)自動(dòng)檢查runState和workerCount,這樣可以防止虛假警報(bào)的增加當(dāng)它不應(yīng)該的時(shí)候,返回false。
// 2. 如果任務(wù)可以成功排隊(duì),那么我們?nèi)匀恍枰獊?lái)再次檢查我們是否應(yīng)該添加線程(因?yàn)樽詮纳洗螜z查后,現(xiàn)有的已經(jīng)死了)或者那樣自進(jìn)入此方法后池就關(guān)閉了。所以我們重新檢查狀態(tài),并在必要時(shí)回滾隊(duì)列停止,或啟動(dòng)一個(gè)新線程(如果沒(méi)有線程)。
// 3.如果我們不能將任務(wù)放入隊(duì)列,那么我們嘗試添加一個(gè)新的線程。如果它失敗了,我們知道我們被關(guān)閉或飽和了所以拒絕這個(gè)任務(wù)。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 第一步
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
// 第二步驟
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 第三步
else if (!addWorker(command, false))
reject(command);
}
五種線程池:
ExecutorService threadPool = null;
threadPool = Executors.newCachedThreadPool();
//有緩沖的線程池,線程數(shù) JVM 控制
threadPool = Executors.newFixedThreadPool(3);
//固定大小的線程池
threadPool = Executors.newScheduledThreadPool(2);
threadPool = Executors.newSingleThreadExecutor();
//單線程的線程池,只有一個(gè)線程在工作
threadPool = new ThreadPoolExecutor();
//默認(rèn)線程池,可控制參數(shù)比較多
ThreadPoolExecutor參數(shù):
public class ThreadPoolExecutor extends AbstractExecutorService {
.....
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue workQueue) ;
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue workQueue,ThreadFactory threadFactory) ;
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue workQueue,RejectedExecutionHandler handler) ;
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,
BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) ;
...
}
參數(shù)含義以及功能:
corePoolSize:核心池的大小,這個(gè)參數(shù)跟后面講述的線程池的實(shí)現(xiàn)原理有非常大的關(guān)系。在創(chuàng)建了線程池后,默認(rèn)情況下,線程池中并沒(méi)有任何線程,而是等待有任務(wù)到來(lái)才創(chuàng)建線程去執(zhí)行任務(wù),除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法,從這2個(gè)方法的名字就可以看出,是預(yù)創(chuàng)建線程的意思,即在沒(méi)有任務(wù)到來(lái)之前就創(chuàng)建corePoolSize個(gè)線程或者一個(gè)線程。默認(rèn)情況下,在創(chuàng)建了線程池后,線程池中的線程數(shù)為0,當(dāng)有任務(wù)來(lái)之后,就會(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:表示線程沒(méi)有任務(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ù)不超過(guò)corePoolSize。但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法,在線程池中的線程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會(huì)起作用,直到線程池中的線程數(shù)為0;unit:參數(shù)keepAliveTime的時(shí)間單位,有7種取值,在TimeUnit類中有7種靜態(tài)屬性:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小時(shí)
TimeUnit.MINUTES; //分鐘
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //納秒
workQueue:一個(gè)阻塞隊(duì)列,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù),這個(gè)參數(shù)的選擇也很重要,會(huì)對(duì)線程池的運(yùn)行過(guò)程產(chǎn)生重大影響,一般來(lái)說(shuō),這里的阻塞隊(duì)列有以下幾種選擇:
ArrayBlockingQueue;
LinkedBlockingQueue;
SynchronousQueue;
ArrayBlockingQueue和PriorityBlockingQueue使用較少,一般使用LinkedBlockingQueue和Synchronous。線程池的排隊(duì)策略與BlockingQueue有關(guān)。
threadFactory:線程工廠,主要用來(lái)創(chuàng)建線程;handler:表示當(dāng)拒絕處理任務(wù)時(shí)的策略,有以下四種取值:ThreadPoolExecutor.AbortPolicy:(默認(rèn))丟棄任務(wù)并拋出RejectedExecutionException異常。ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù),但是不拋出異常。ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過(guò)程)ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
四種拒絕策略:
RejectedExecutionHandler rejected = null;
rejected = new ThreadPoolExecutor.AbortPolicy();
//默認(rèn),隊(duì)列滿了丟任務(wù)拋出異常
rejected = new ThreadPoolExecutor.DiscardPolicy();
//隊(duì)列滿了丟任務(wù)不拋異常
rejected = new ThreadPoolExecutor.DiscardOldestPolicy();
//將最早進(jìn)入隊(duì)列的任務(wù)刪,之后再嘗試加入隊(duì)列
rejected = new ThreadPoolExecutor.CallerRunsPolicy();
//如果添加到線程池失敗,那么主線程會(huì)自己去執(zhí)行該任務(wù);如果執(zhí)行程序已關(guān)閉(主線程運(yùn)行結(jié)束),則會(huì)丟棄該任務(wù)
當(dāng)然也可以根據(jù)應(yīng)用場(chǎng)景實(shí)現(xiàn) RejectedExecutionHandler 接口,自定義飽和策略,如記錄 日志或持久化存儲(chǔ)不能處理的任務(wù)
三種阻塞隊(duì)列:
BlockingQueue workQueue = null;
workQueue = new ArrayBlockingQueue<>(5);
//基于數(shù)組的先進(jìn)先出隊(duì)列,有界
workQueue = new LinkedBlockingQueue<>();
//基于鏈表的先進(jìn)先出隊(duì)列,無(wú)界
workQueue = new SynchronousQueue<>();
//無(wú)緩沖的等待隊(duì)列,無(wú)界 