線程池
線程池的優(yōu)點
- 重復(fù)利用已經(jīng)創(chuàng)建的線程,減少創(chuàng)建線程和銷毀線程的開銷
- 提高響應(yīng)速度,不需要等到線程創(chuàng)建就能立即執(zhí)行
- 使用線程池可以進行統(tǒng)一分配,調(diào)優(yōu)和監(jiān)控
- 總的來說:降低資源消耗,提高響應(yīng)速度,提高線程可管理性
線程池原理

- 提交任務(wù)
- 核心線程池(corePoolSize)是否已經(jīng)滿,如果未滿的話就創(chuàng)建線程執(zhí)行任務(wù)
- 否則查看隊列(BlockingQueue)是否已滿,未滿的話,將任務(wù)存儲在隊列里
- 如果已經(jīng)滿了,看線程池(maximumPoolSize)是否已滿,如果滿的話按照拒絕處理任務(wù)策略(handler)處理無法執(zhí)行的任務(wù)
- 如果未滿,創(chuàng)建線程執(zhí)行任務(wù)
ThreadPoolExecutor構(gòu)造參數(shù)
- corePoolSize:核心池的大小,構(gòu)建線程池后,并不會創(chuàng)建線程,當(dāng)前線程數(shù)如果小于corePoolSize時,當(dāng)要執(zhí)行任務(wù)時,創(chuàng)建一個線程。當(dāng)當(dāng)前線程數(shù)等于corePoolSize,會將任務(wù)放入隊列中
- maximumPoolSize:線程池最大數(shù),也就是線程最多能創(chuàng)建的線程
- keepAliveTime:工作線程空閑后,保持存活的時間。默認情況下,如果當(dāng)前線程數(shù)大于corePoolSize,那么一個線程如果沒有任務(wù),當(dāng)空閑的時間大于keepAliveTime時,會終止該線程,直到線程數(shù)不超過corePoolSize
- workQueue:存儲任務(wù)的隊列,有幾種種類型隊列ArrayBlockingQueue(有界緩沖區(qū),基于數(shù)組的隊列,先進先出,必須指定大小,可以設(shè)置是否保持公平,以FIFO順序訪問),LinkedBlockingQueue(基于鏈表的隊列,如果沒有指定大小,默認為Integer.MAX_VALUE),SynchronousQueue(無界線程池,不管多少任務(wù)提交進來,直接運行)
- ThreadFactory:線程工廠,用來創(chuàng)建線程,通過線程工廠可以給創(chuàng)建的線程設(shè)置名字
- rejectedExecutionHandler:拒絕處理任務(wù)的策略AbortPolicy(直接放棄任務(wù),拋出RejectedExecutionException異常),DiscardPolicy(放棄任務(wù),不拋出異常),DiscardOldestPolicy(放棄最舊的未處理請求,然后重試 execute;如果執(zhí)行程序已關(guān)閉,則會丟棄該任務(wù)),CallerRunsPolicy(它直接在 execute 方法的調(diào)用線程中運行被拒絕的任務(wù);如果執(zhí)行程序已關(guān)閉,則會丟棄該任務(wù))
ThreadPoolExecutor重要方法
- execute:在將來某個時間執(zhí)行給定任務(wù)
- submit:提交一個任務(wù)用于執(zhí)行,并返回一個表示該任務(wù)的 Future,和execute不同的是返回的是一個Future,可以在任務(wù)執(zhí)行完畢之后得到任務(wù)執(zhí)行結(jié)果
- shutdown:按過去執(zhí)行已提交任務(wù)的順序發(fā)起一個有序的關(guān)閉,但是不接受新任務(wù)。也就是說,中斷沒有正在執(zhí)行任務(wù)的線程,等待任務(wù)執(zhí)行完畢。
- shutdownnow: 嘗試停止所有的活動執(zhí)行任務(wù)、暫停等待任務(wù)的處理,并返回等待執(zhí)行的任務(wù)列表。
線程池狀態(tài)
volatile int runState;
static final int RUNNING = 0;
static final int SHUTDOWN = 1;
static final int STOP = 2;
static final int TERMINATED = 3;
- RUNNING:創(chuàng)建線程池后,初始狀態(tài)為RUNNING
- SHUTDOWN:執(zhí)行shutdown方法后,線程池處于SHUTDOWN狀態(tài)
- STOP:執(zhí)行shutdownNow方法后,線程池處于STOP狀態(tài)
- TERMINATED:當(dāng)線程池處于SHUTDOWN或STOP狀態(tài),并且所有工作線程已經(jīng)銷毀,任務(wù)緩存隊列已經(jīng)清空或執(zhí)行結(jié)束后,線程池被設(shè)置為TERMINATED狀態(tài)。
源碼分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
if (runState == RUNNING && workQueue.offer(command)) {
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
else if (!addIfUnderMaximumPoolSize(command))
reject(command); // is shutdown or saturated
}
}
- command是否為空,是的話拋出異常
- 如果當(dāng)前線程是否小于corePoolSize,執(zhí)行addIfUnderCorePoolSize方法,創(chuàng)建線程并執(zhí)行任務(wù)
- 如果當(dāng)前線程線程數(shù)大于等于corePoolSize或者執(zhí)行addIfUnderCorePoolSize返回false,將當(dāng)前任務(wù)放到隊列中
- 如果線程池狀態(tài)不是RUNNING狀態(tài)或者任務(wù)無法加入到隊列,并且線程數(shù)大于最大線程數(shù),執(zhí)行reject方法
- 流程跟上面的線程池原理相同
配置線程池
- cpu密集型和io密集型線程數(shù)的選擇,cpu密集型不需要太多的線程,可以充分利用cpu資源,io密集型適當(dāng)多線程,io阻塞時可以切換至另一線程。
- 優(yōu)先級不同的的任務(wù)可以使用PriorityBlockingQueue來處理
- 建議使用有界隊列,能夠增加系統(tǒng)的穩(wěn)定性(如果使用無界隊列,當(dāng)出現(xiàn)問題時候,隊列無限增長,此時可能會占用大量內(nèi)存,導(dǎo)致系統(tǒng)出現(xiàn)問題)和預(yù)警能力(當(dāng)出現(xiàn)隊列占滿的時候,拋出異常,可以讓開發(fā)人員及時發(fā)現(xiàn))
線程池使用
public static void main(String[] args)
{
final Vector<Integer> vector = new Vector<Integer>();
//corePoolSize,maximumPoolSize,keepAliveTime,TimeUnit,BlockingQueue
ThreadPoolExecutor tp = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10));
final Random random = new Random();
System.out.println(tp.getPoolSize());
for (int i = 0; i < 20; i++)
{
tp.execute(new Runnable()
{
public void run()
{
vector.add(random.nextInt());
}
});
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO 自動生成的 catch 塊
e.printStackTrace();
}
tp.shutdown();
System.out.println("已完成的任務(wù):"+tp.getCompletedTaskCount());
System.out.println("活動的線程數(shù):"+tp.getActiveCount());
System.out.println("list大?。?+vector.size());
}
- 上面的代碼我們自己構(gòu)建了一個ThreadPoolExecutor,而Executor給我們提供了幾個靜態(tài)方法用于創(chuàng)建線程池,本質(zhì)上只是設(shè)置了給定的參數(shù)而已
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
- FixedThreadPool,顧名思義,一個固定大小的線程池,隊列使用的無限制大小的鏈表阻塞隊列
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
- 單線程線程池,同樣隊列使用的無限制大小的鏈表阻塞隊列
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
- 無界線程池,無論多少任務(wù),直接運行,如果線程池長度超過處理需要,可靈活回收空閑線程,若無可回收,則新建線程
我覺得分享是一種精神,分享是我的樂趣所在,不是說我覺得我講得一定是對的,我講得可能很多是不對的,但是我希望我講的東西是我人生的體驗和思考,是給很多人反思,也許給你一秒鐘、半秒鐘,哪怕說一句話有點道理,引發(fā)自己內(nèi)心的感觸,這就是我最大的價值。(這是我喜歡的一句話,也是我寫博客的初衷)
作者:jiajun 出處: http://www.cnblogs.com/-new/