一、什么是線程池渊鞋?
線程的創(chuàng)建和銷毀對(duì)于系統(tǒng)來(lái)說(shuō)是一種較大的開(kāi)銷胀莹,線程池通過(guò)多個(gè)任務(wù)重用線程基跑,線程創(chuàng)建的開(kāi)銷就被分?jǐn)偟搅硕鄠€(gè)任務(wù)上,而且請(qǐng)求到達(dá)時(shí)線程已經(jīng)存在描焰,消除了等待線程創(chuàng)建帶來(lái)的延遲媳否,使得程序響應(yīng)更快。
二荆秦、線程池的優(yōu)點(diǎn)是什么篱竭?
線程池主要用來(lái)解決線程生命周期開(kāi)銷問(wèn)題和資源不足問(wèn)題。如果每當(dāng)一個(gè)請(qǐng)求到達(dá)就創(chuàng)建一個(gè)新線程步绸,開(kāi)銷是挺大的掺逼,甚至在創(chuàng)建和銷毀線程上花費(fèi)的時(shí)間和消耗的資源要大于處理用戶請(qǐng)求的時(shí)間和資源。另外如果創(chuàng)建線程太多瓤介,系統(tǒng)會(huì)由于過(guò)度消耗內(nèi)存和切換過(guò)度頻繁導(dǎo)致系統(tǒng)資源不足吕喘。因而可以通過(guò)線程池盡可能減少創(chuàng)建和銷毀線程的次數(shù),利用已有的對(duì)象進(jìn)行服務(wù)刑桑。
三氯质、線程池實(shí)現(xiàn)類
JDK中提供了java.util.concurrent.ThreadPoolExecutor
類來(lái)實(shí)現(xiàn)線程池,其構(gòu)造方法如下:
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
我們先對(duì)構(gòu)造方法中的參數(shù)進(jìn)行介紹:
1祠斧、int corePoolSize
核心池的大小闻察,默認(rèn)情況下創(chuàng)建線程池之后線程池沒(méi)有線程,而是等待任務(wù)到來(lái)才創(chuàng)建線程去執(zhí)行任務(wù)琢锋,除非是調(diào)用了prestartAllCoreThreads()
方法辕漂,進(jìn)行線程的預(yù)創(chuàng)建,創(chuàng)建corePoolSize
個(gè)線程吴超。
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
2钮热、int maximumPoolSize
線程池最大線程個(gè)數(shù),表示線程池中最多能創(chuàng)建的線程個(gè)數(shù)
3烛芬、long keepAliveTime
表示線程多久沒(méi)有任務(wù)執(zhí)行就會(huì)被銷毀
默認(rèn)情況下隧期,當(dāng)線程數(shù)量大于corePoolSize
時(shí)飒责,keepAliveTime
才會(huì)生效,銷毀線程池中線程直到線程數(shù)量不大于corePoolSize
仆潮;
但是如果調(diào)用了allowCoreThreadTimeOut(boolean)
方法宏蛉,傳入?yún)?shù)為true
時(shí),如注釋所說(shuō):核心線程也會(huì)被銷毀性置,直到線程數(shù)量為0拾并。
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*如果為false(默認(rèn)值),則即使處于空閑狀態(tài)鹏浅,核心線程也保持活動(dòng)
*狀態(tài)嗅义。如果為true,則核心線程使用keepAliveTime來(lái)超時(shí)等待工作隐砸。
*/
private volatile boolean allowCoreThreadTimeOut;
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
//銷毀空閑線程
interruptIdleWorkers();
}
}
4之碗、TimeUnit unit
上一個(gè)參數(shù)keepAliveTime
的時(shí)間單位,有7種靜態(tài)屬性取值:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小時(shí)
TimeUnit.MINUTES; //分鐘
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微秒
TimeUnit.NANOSECONDS; //納秒
5季希、BlockingQueue<Runnable> workQueue
阻塞隊(duì)列褪那,用來(lái)存儲(chǔ)等待執(zhí)行的任務(wù),有以下三種:
SynchronousQueue
(默認(rèn))直接提交策略式塌;
LinkedBlockingQueue
無(wú)界隊(duì)列策略博敬;
ArrayBlockingQueue
有界隊(duì)列策略。
(1)峰尝、SynchronousQueue
(默認(rèn))直接提交策略
工作隊(duì)列不保存任何的任務(wù)等待執(zhí)行偏窝,而是直接提交給線程進(jìn)行執(zhí)行;如果沒(méi)有可用于立即執(zhí)行任務(wù)的線程武学,則會(huì)創(chuàng)建一個(gè)新的線程來(lái)執(zhí)行祭往。此策略下maximumPoolSize
將會(huì)失效。
(2)劳淆、LinkedBlockingQueue
無(wú)界隊(duì)列策略
無(wú)界指的是工作隊(duì)列大小,可以指定大小默赂,如果不指定沛鸵,默認(rèn)為Integer.MAX_VALUE
,如果添加速度大于刪除速度的時(shí)候缆八,有可能會(huì)內(nèi)存溢出曲掰。
(3)、ArrayBlockingQueue
有界隊(duì)列策略
有界也就意味著奈辰,它的大小是有限制的栏妖。所以在創(chuàng)建 ArrayBlockingQueue
時(shí),必須要給它指定一個(gè)隊(duì)列的大薪鼻 吊趾;可以防止資源耗盡的情況發(fā)生宛裕。
6、ThreadFactory threadFactory
線程工廠论泛,用來(lái)創(chuàng)建線程的工廠類
ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().
setNameFormat("demo-pool-%d").build();
7揩尸、RejectedExecutionHandler handler
線程池拒絕策略,當(dāng)線程池的任務(wù)緩存隊(duì)列已滿并且線程池中的線程數(shù)目達(dá)到maximumPoolSize屁奏,如果還有任務(wù)到來(lái)就會(huì)采取任務(wù)拒絕策略岩榆,有以下幾種:
(1)、AbortPolicy
java線程池默認(rèn)的阻塞策略坟瓢,即不執(zhí)行此新任務(wù)勇边,而且直接拋出一個(gè)運(yùn)行時(shí)異常(RejectedExecutionException
)
//丟棄任務(wù)并拋出RejectedExecutionException異常。
public static class AbortPolicy implements RejectedExecutionHandler {
public AbortPolicy() { }
// 拋出異常
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString());
}
}
(2)折联、DiscardPolicy
直接丟棄任務(wù)粒褒,不執(zhí)行,但是不拋出異常
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
(3)崭庸、DiscardOldestPolicy
當(dāng)有任務(wù)添加到線程池被拒絕時(shí)怀浆,線程池會(huì)丟棄阻塞隊(duì)列中位于頭部的任務(wù),將被拒絕的任務(wù)添加到末尾怕享,然后重試執(zhí)行程序执赡,如果再次失敗,則重復(fù)此過(guò)程
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
(4)函筋、CallerRunsPolicy
由調(diào)用線程來(lái)執(zhí)行被拒絕的任務(wù)沙合,如果執(zhí)行程序已關(guān)閉,則會(huì)丟棄該任務(wù)
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}