線程池實現(xiàn)類ThreadPoolExecutor是在java.util.concurrent下的贯溅,從JDK1.5開始支持線程池實現(xiàn)類ThreadPoolExecutor.
該類有四個構(gòu)造函數(shù)(不含無參構(gòu)造函數(shù)),分別為:
// 常用的是這種燥滑,使用默認(rèn)的線程工廠和拒絕策略
1改鲫、ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue)
// 用戶自定義線程工廠
2窗市、ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory)
// 用戶自定義線程池飽和/執(zhí)行拒絕策略
3肮街、ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,
RejectedExecutionHandler handler)
// 用戶自定義線程工廠和線程池飽和/執(zhí)行拒絕策略
4风题、ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
其中:1、2嫉父、3構(gòu)造函數(shù)均調(diào)用this(args...)構(gòu)造函數(shù)沛硅,即構(gòu)造函數(shù)4。
Executors類提供了默認(rèn)的ThreadFactory(線程工廠),即Executors.defaultThreadFactory()绕辖,
ThreadPoolExecutor提供了默認(rèn)的線程池飽和和執(zhí)行拒絕策略摇肌,private static final RejectedExecutionHandler defaultHandler =new AbortPolicy();
線程池實現(xiàn)類的構(gòu)造函數(shù)參數(shù):
corePoolSize(線程池核心線程大小):當(dāng)提交一個任務(wù)到線程池時,線程池會創(chuàng)建一個線程來執(zhí)行任務(wù)引镊,即使其他空閑的基本線程能夠執(zhí)行新任務(wù)也會創(chuàng)建線程朦蕴,當(dāng)任務(wù)數(shù)大于核心線程數(shù)的時候就不會再創(chuàng)建。在這里要注意一點弟头,線程池剛創(chuàng)建的時候,其中并沒有創(chuàng)建任何線程涉茧,而是等任務(wù)來才去創(chuàng)建線程赴恨,除非調(diào)用了prestartAllCoreThreads()或者prestartCoreThread()方法 ,這樣才會預(yù)先創(chuàng)建好corePoolSize個線程或者一個線程伴栓。
maximumPoolSize(線程池最大線程數(shù)):線程池允許創(chuàng)建的最大線程數(shù)伦连,如果隊列滿了,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù)钳垮,則線程池會再創(chuàng)建新的線程執(zhí)行任務(wù)惑淳。值得注意的是,如果使用了無界隊列饺窿,此參數(shù)就沒有意義了歧焦。
keepAliveTime(線程活動保持時間):此參數(shù)默認(rèn)在線程數(shù)大于corePoolSize的情況下才會起作用, 當(dāng)線程(默認(rèn)是針對非核心線程)的空閑時間達(dá)到keepAliveTime的時候就會終止肚医,直至線程數(shù)目小于corePoolSize绢馍。不過如果調(diào)用allowCoreThreadTimeOut方法向瓷,則當(dāng)線程數(shù)目小于corePoolSize的時候也會起作用.
unit(keelAliveTime的時間單位):keelAliveTime的時間單位,一共有7種舰涌,在這里就不列舉了猖任。
workQueue(阻塞隊列):阻塞隊列,用來存儲等待執(zhí)行的任務(wù)瓷耙,這個參數(shù)也是非常重要的朱躺,在這里簡單介紹一下幾個阻塞隊列。
????1)ArrayBlockingQueue:這是一個基于數(shù)組結(jié)構(gòu)的有界阻塞隊列搁痛,此隊列按照FIFO的原則對元素進(jìn)行排序室琢。
????2)LinkedBlockingQueue:一個基于鏈表結(jié)構(gòu)的阻塞隊列,此隊列按照FIFO排序元素落追,吞吐量通常要高于ArrayBlockingQueue盈滴。靜態(tài)工廠方法Executors.newFixedThreadPool()就是使用了這個隊列。
????3)SynchronousQueue:一個不存儲元素的阻塞隊列轿钠。每個插入操作必須等到另一個線程調(diào)用移除操作巢钓,否則插入操作一直處于阻塞狀態(tài)。吞吐量通常要高于LinkedBlockingQueue疗垛,靜態(tài)工廠方法Executors.newCachedThreadPool()就使用了這個隊列症汹。
????4)PriorityBlockingQueue:一個具有優(yōu)先級的無阻塞隊列。
handler(飽和策略)贷腕;當(dāng)線程池和隊列都滿了背镇,說明線程池已經(jīng)處于飽和狀態(tài)了,那么必須采取一種策略來處理還在提交過來的新任務(wù)泽裳。這個飽和策略默認(rèn)情況下是AbortPolicy瞒斩,表示無法處理新任務(wù)時拋出異常。共有四種飽和策略提供涮总,當(dāng)然我們也可以選擇自己實現(xiàn)飽和策略胸囱。
AbortPolicy:直接丟棄并且拋出RejectedExecutionException異常,這種是默認(rèn)的飽和策略
CallerRunsPolicy:只用調(diào)用者所在線程來運行任務(wù)瀑梗,如果線程池處于Running狀態(tài)烹笔,直接在提交任務(wù)的線程中執(zhí)行任務(wù);如果線程池不處于Running狀態(tài)抛丽,直接丟棄任務(wù)谤职。
DiscardOldestPolicy:丟棄隊列里最近的一個任務(wù),并執(zhí)行當(dāng)前任務(wù)亿鲜。
DiscardPolicy:丟棄任務(wù)并且不拋出異常允蜈,如果線程池處于Running狀態(tài),從阻塞隊列中移除頭部任務(wù)并重新調(diào)用execute方法。
ThreadPoolExecutor類中的幾個關(guān)鍵屬性及方法源碼解析:
查看ThreadPoolExecutor源碼陷寝,可以發(fā)現(xiàn)锅很,有以下屬性:
//ctl是線程池主要的控制狀態(tài),是一個復(fù)合類型的變量凤跑,其中包括了兩個概念爆安。
// ctl的高3位代表線程池的狀態(tài),低29位代表workerCount
// workerCount:表示有效的線程數(shù)目(低29位)
// runState:線程池里線程的運行狀態(tài)(高3位)
// 線程池的控制狀態(tài)主要分為:RUNNING仔引、SHUTDOWN扔仓、STOP、TIDYING咖耘、TERMINATE
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));?
// COUNT_BITS用來表示線程池數(shù)量的位數(shù)翘簇,Integer.SIZE=32,因此COUNT_BITS=29儿倒,減3是為線程池運行狀態(tài)預(yù)留3位bit位版保。
private static final int COUNT_BITS = Integer.SIZE - 3;?
// 線程池最大線程數(shù)量,線程池最大線程數(shù)量為2^29-1個
private static final int CAPACITY = (1 << COUNT_BITS) - 1;?
// runState is stored in the high-order bits夫否,線程池運行狀態(tài)彻犁,存儲在ctl變量的高位(高3位)
// 高3位為111,則是在RUNNING狀態(tài)凰慈,
private static final int RUNNING = -1 << COUNT_BITS;?
// 高3位位000汞幢,則是在SHUTDOWN狀態(tài)
private static final int SHUTDOWN = 0 << COUNT_BITS;? ? ? // 0?
// 高3位為001,則是在STOP狀態(tài)
private static final int STOP = 1 << COUNT_BITS;?
// 高3位為010微谓,則是在TIDYING狀態(tài)
private static final int TIDYING = 2 << COUNT_BITS;?
// 高3位為110森篷,則是在TERMINATED狀態(tài)
private static final int TERMINATED = 3 << COUNT_BITS;?
// Packing and unpacking ctl?
// 獲取當(dāng)前運行狀態(tài),通過對CAPACITY取反豺型,然后和傳進(jìn)來的參數(shù)進(jìn)行與運算
private static int runStateOf(int c) { return c & ~CAPACITY; }?
// 獲取當(dāng)前有效的線程數(shù)量
private static int workerCountOf(int c) { return c & CAPACITY; }
?private static int ctlOf(int rs, int wc) { return rs | wc; }??
// 阻塞隊列
private final BlockingQueue?workQueue;
// 可重入鎖仲智,訪問workers集合、訪問largestPoolSize等線程池的統(tǒng)計型變量触创、執(zhí)行shutdown方法坎藐、執(zhí)行shutdownNow方法都需要獲取該鎖
private final ReentrantLock mainLock = new ReentrantLock();
// 線程池內(nèi)的有效線程
private final HashSet<Worker> workers = new HashSet<Worker>();
//和mainLock綁定的Condition對象,執(zhí)行awaitTermination方法和tryTerminate方法時使用該Condition對象
private final Condition termination = mainLock.newCondition();
// 線程工廠
private volatile ThreadFactory threadFactory;
// 線程池達(dá)到飽和后的拒絕策略
private volatile RejectedExecutionHandler handler;
線程池的控制(運行)狀態(tài)
線程池的控制狀態(tài)主要分為:RUNNING哼绑、SHUTDOWN、STOP碉咆、TIDYING抖韩、TERMINATE
每種控制狀態(tài)下,對新創(chuàng)建的線程(任務(wù))和已在阻塞隊列的線程(任務(wù))的策略都有不同疫铜,
1)RUNNING狀態(tài):線程池可以接受新任務(wù)并且處理已經(jīng)在阻塞隊列的任務(wù)茂浮。
2)SHUTDOWN狀態(tài):?線程池不接受新任務(wù),但是處理已經(jīng)在阻塞隊列的任務(wù)。
3)STOP狀態(tài):?線程池不接受新任務(wù)席揽,也不處理阻塞隊列里的任務(wù)顽馋,并且會中斷正在處理的任務(wù)。
4)TIDYING狀態(tài):線程池所有任務(wù)都被中止幌羞,workerCount(有效線程數(shù)量)是0寸谜,線程狀態(tài)轉(zhuǎn)化為TIDYING并且調(diào)用terminated()鉤子方法。
5)TERMINATE狀態(tài):terminated()鉤子方法已經(jīng)完成属桦。
線程池執(zhí)行線程(調(diào)用execute(Runnable command)方法)流程:
1熊痴、首先判斷任務(wù)是否為空,空則拋出空指針異常(if command==null throw new NullPointerException();)
2聂宾、command不為空則獲取線程池控制狀態(tài)ctl值(包括:運行狀態(tài)和有效線程數(shù))果善,判斷有效線程數(shù)是否小于corePoolSize,小于添加到worker集合當(dāng)中執(zhí)行系谐,如成功巾陕,則返回(執(zhí)行線程command任務(wù)),失敗的話再接著獲取線程池控制狀態(tài)纪他,因為只有狀態(tài)變了才會失敗鄙煤,所以重新獲取。
3止喷、判斷線程池是否處于運行狀態(tài)馆类,是的話則添加command到阻塞隊列,加入時也會再次獲取狀態(tài)并且檢測
? 狀態(tài)是否不處于運行狀態(tài)弹谁,不處于的話則將command從阻塞隊列移除乾巧,并且拒絕任務(wù)
4、如果線程池里沒有了線程(workerCountOf 方法返回值為0)预愤,則創(chuàng)建新的線程去執(zhí)行獲取阻塞隊列的任務(wù)執(zhí)行沟于。
5、如果以上都沒執(zhí)行成功植康,則需要開啟最大線程池里的線程來執(zhí)行任務(wù)旷太,失敗的話就丟棄。
線程池執(zhí)行線程的流程圖例销睁,(借用作者:KingJack文章配圖):