為什么使用線程池
使用線程池的好處是減少在創(chuàng)建和銷(xiāo)毀線程上所花的時(shí)間和系統(tǒng)資源的開(kāi)銷(xiāo)沪曙,節(jié)省資源鹊奖,提高效率吠裆。如果不使用線程池渐逃,有可能會(huì)造成系統(tǒng)創(chuàng)建大量同類(lèi)線程而導(dǎo)致內(nèi)存耗盡或者“過(guò)度切換”的問(wèn)題够掠。所以線程資源最好由線程池提供,不要在應(yīng)用中自行顯示創(chuàng)建線程朴乖。
Executor
Executor是java中線程池的核心接口祖屏,只有一個(gè)方法execute(Runnable command)
public interface Executor {
/**
* Executes the given command at some time in the future. The command
* may execute in a new thread, in a pooled thread, or in the calling
* thread, at the discretion of the {@code Executor} implementation.
*
* @param command the runnable task
* @throws RejectedExecutionException if this task cannot be
* accepted for execution
* @throws NullPointerException if command is null
*/
void execute(Runnable command);
}
類(lèi)關(guān)系說(shuō)明
ThreadPoolExecutor是Executor接口的主要實(shí)現(xiàn)類(lèi)
ExecutorService是Executor的子接口,增加了一些對(duì)線程池的控制方法买羞,關(guān)閉線程池袁勺,批量調(diào)用等
AbstractExecutorService是一個(gè)抽象類(lèi),對(duì)ExecutorService的方法提供了默認(rèn)實(shí)現(xiàn)畜普,ThreadPoolExecutor繼承此類(lèi)
ThreadPoolExecutor
構(gòu)造方法
ThreadPoolExecutor是線程池的真正實(shí)現(xiàn)類(lèi)期丰,可以通過(guò)構(gòu)造方法的各種參數(shù)組合來(lái)配置不同的線程池援奢。構(gòu)造方法有以下四種
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
先來(lái)解釋一下各個(gè)參數(shù):
-
int corePoolSize
該線程池中核心線程數(shù)掰派。線程池在新建線程的時(shí)候困介,如果當(dāng)前活動(dòng)線程總數(shù)小于核心線程數(shù)帆调,則會(huì)新建核心線程,直到達(dá)到corePoolSize癣漆,如果超過(guò)核心線程數(shù)骑祟,則會(huì)創(chuàng)建臨時(shí)線程晦攒,也就是非核心線程逛犹,兩者的區(qū)別在于非核心線程在執(zhí)行完任務(wù)后超過(guò)規(guī)定時(shí)長(zhǎng)會(huì)被銷(xiāo)毀端辱,而核心線程執(zhí)行完任務(wù)會(huì)一直存在,不論是否閑置虽画。
-
int maximumPoolSize
該線程池中線程總數(shù)的最大值舞蔽。線程總數(shù)=核心線程數(shù)+非核心線程數(shù)
-
long keepAliveTime
該線程池中非核心線程的存活時(shí)間。一個(gè)非核心線程码撰,如果處于閑置狀態(tài)渗柿,當(dāng)閑置時(shí)長(zhǎng)超過(guò)這個(gè)參數(shù)設(shè)置的時(shí)間,則會(huì)被銷(xiāo)毀脖岛,如果指定ThreadPoolExecutor的allowCoreThreadTimeOut這個(gè)屬性為true朵栖,那么這個(gè)參數(shù)會(huì)同樣作用于核心線程
-
TimeUnit unit
keepAliveTime的單位。TimeUnit是一個(gè)枚舉類(lèi)型柴梆,其包括:
NANOSECONDS : 微毫秒 1微毫秒 = 1微秒 / 1000</br>
MICROSECONDS : 微秒 1微秒 = 1毫秒 / 1000</br>
MILLISECONDS : 毫秒 1毫秒 = 1秒 /1000</br>
SECONDS : 秒</br>
MINUTES : 分</br>
HOURS : 小時(shí)</br>
DAYS : 天</br> -
BlockingQueue<Runnable> workQueue
該線程池中的任務(wù)隊(duì)列混槐。維護(hù)著所有等待執(zhí)行的Runnable對(duì)象,常用的workQueue有:
- SynchronousQueue:同步隊(duì)列,一個(gè)沒(méi)有容量大小的阻塞隊(duì)列轩性,將任務(wù)同步交付給工作線程,也就是說(shuō)當(dāng)這個(gè)隊(duì)列接收到任務(wù)的時(shí)候,會(huì)直接提交給線程進(jìn)行處理揣苏,如果核心線程都已經(jīng)在工作了悯嗓,則會(huì)創(chuàng)建非核心線程,直到線程數(shù)達(dá)到maximumPoolSize卸察,從而執(zhí)行拒絕策略
- LinkedBlockingQueue:構(gòu)造函數(shù)不傳容量大小會(huì)默認(rèn)為Integer.MAX_VALUE脯厨,一般都使用默認(rèn)值,所以當(dāng)這個(gè)隊(duì)列接收到任務(wù)時(shí)坑质,如果當(dāng)前線程數(shù)小于核心線程數(shù)合武,則會(huì)創(chuàng)建核心線程,否則會(huì)進(jìn)入隊(duì)列等待涡扼,又因?yàn)殛?duì)列默認(rèn)大小是Integer.MAX_VALUE稼跳,即所有超過(guò)核心線程數(shù)的任務(wù)量都將被添加到隊(duì)列中去,從而導(dǎo)致maximumPoolSize參數(shù)失效吃沪,因?yàn)檫@個(gè)隊(duì)列幾乎不可能滿(mǎn)
- ArrayBlockingQueue:必須要限定容量大小的隊(duì)列汤善,當(dāng)接收到任務(wù)時(shí),如果沒(méi)有達(dá)到核心線程數(shù)票彪,則新建核心線程處理任務(wù)红淡,如果核心線程已滿(mǎn),則進(jìn)入隊(duì)列等待降铸,如果隊(duì)列也滿(mǎn)了在旱,則會(huì)創(chuàng)建非核心線程處理任務(wù),如果總線程數(shù)達(dá)到了maximumPoolSize推掸,則會(huì)執(zhí)行拒絕策略
- PriorityBlockingQueue:無(wú)界的阻塞隊(duì)列桶蝎,類(lèi)似于LinkedBlockingQueue,但其所含對(duì)象的順序并不是FIFO终佛,而是根據(jù)對(duì)象的自然排序順序或者構(gòu)造函數(shù)的Comparator決定的順序
ThreadFactory threadFactory:創(chuàng)建線程的方式俊嗽。一般不用,默認(rèn)實(shí)現(xiàn)即可
-
RejectedExecutionHandler handler:拒絕策略铃彰。當(dāng)線程數(shù)達(dá)到最大值且隊(duì)列已滿(mǎn)時(shí)會(huì)執(zhí)行拒絕策略绍豁,ThreadPoolExecutor自己提供了四個(gè)拒絕策略:
- AbortPolicy:默認(rèn)策略,直接放棄任務(wù)并拋出RejectedExecutionException異常
- CallerRunsPolicy:用調(diào)用者的線程執(zhí)行任務(wù)
- DiscardOldestPolicy:拋棄隊(duì)列中最老的那個(gè)任務(wù)牙捉,也就是排隊(duì)時(shí)間最長(zhǎng)的那個(gè)任務(wù)
- DiscardPolicy:拋棄當(dāng)前將要加入隊(duì)列的任務(wù)
主要方法
- execute:開(kāi)始執(zhí)行一個(gè)任務(wù)
- shutdown:?jiǎn)?dòng)之前提交的任務(wù)會(huì)執(zhí)行完并有序關(guān)閉竹揍,不接受新任務(wù),如果已經(jīng)關(guān)閉邪铲,調(diào)用沒(méi)有任何效果
- shutdownNow:試圖立即停止所有積極執(zhí)行的任務(wù)芬位,停止處理等待的任務(wù),并返回未執(zhí)行的任務(wù)列表
- remove:取消在隊(duì)列中等待還未執(zhí)行的任務(wù)带到,已執(zhí)行的無(wú)法取消
當(dāng)然還有一系列的getXxx方法昧碉,方便對(duì)線程池的監(jiān)控
總結(jié)
引用《阿里巴巴Java開(kāi)發(fā)手冊(cè)》中的一段話來(lái)總結(jié)一下
【強(qiáng)制】線程池不允許使用 Executors 去創(chuàng)建,而是通過(guò) ThreadPoolExecutor 的方式,這樣的處理方式讓寫(xiě)的同學(xué)更加明確線程池的運(yùn)行規(guī)則被饿,規(guī)避資源耗盡的風(fēng)險(xiǎn)四康。
說(shuō)明:Executors 返回的線程池對(duì)象的弊端如下:
1)FixedThreadPool 和 SingleThreadPool:
允許的請(qǐng)求隊(duì)列長(zhǎng)度為 Integer.MAX_VALUE,可能會(huì)堆積大量的請(qǐng)求狭握,從而導(dǎo)致 OOM闪金。
2)CachedThreadPool 和 ScheduledThreadPool:
允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE,可能會(huì)創(chuàng)建大量的線程论颅,從而導(dǎo)致 OOM哎垦。
一個(gè)線程池在應(yīng)用中如果不再被引用且沒(méi)有剩余的線程時(shí),這個(gè)線程池會(huì)被自動(dòng)的shutdown恃疯。因此如果你想在忘記執(zhí)行shutdown方法時(shí)也能正常的關(guān)閉線程池漏设,建議設(shè)置一個(gè)有限的keepAliveTime,同時(shí)也執(zhí)行下 allowCoreThreadTimeOut(true)