1:先看下線程池屬性配置
public ThreadPoolExecutor(int corePoolSize, //核心線程池個數
int maximumPoolSize, //最大線程池個數
long keepAliveTime, //非核心線程存活時間
TimeUnit unit, //時間格式
BlockingQueue<Runnable> workQueue, //存放Runnable的工作隊列
ThreadFactory threadFactory, //創建線程所需工廠
RejectedExecutionHandler handler //超出workQueue最大等待隊列與maximumPoolSize之和會回調此接口)
1:corePoolSize(核心線程池個數)核心線程會一直存在,並且一直運行,知道關閉線程池或者線程被中斷。
2:maximumPoolSize(最大線程池個數)就是該線程池允許創建線程的最大個數。
3:unit(時間格式)時,分,秒等。
4:workQueue(存放Runnable的工作隊列)
(1)當corePoolSize爲5,workQueue的長度爲5,則同時創建5個核心線程取執行這5個工作隊列。也就是說workQueue的長度小於等於corePoolSize時會創建workQueue長度的線程取執行工作隊列(我使用JDK1.8是這樣的,1.6的不確定)。
(2)當工作隊列workQueue的size大於核心線程池數並且小於阻塞隊列的個數(用ArrayBlockingQueue可以設置等待隊列的個數),則只會創建全部的核心線程取執行工作隊列裏的數據,其他隊列處於阻塞狀態。
(3)當工作隊列workQueue的size大於核心線程池數並且大於等待隊列的個數,則會新建線程執行隊列。新建線程個數=工作隊列個數 - 核心線程池數 - 阻塞隊列數。
(3)當工作隊列workQueue的size > (maximumPoolSize+工作隊阻塞待個數) 會回調 handler 將超出的隊列拋出。需要在回調處將隊列重新加到線程池裏,否則該隊裏的功能將不再執行。此時回調與執行execute在同一個線程,若是主線程,隊列一直處於超出狀態,主線程會卡死。
2:內部執行原理
(1)調用執行方法
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)) // 當工作隊列workQueue的size > (maximumPoolSize+工作隊列阻塞個數)
reject(command);
}
(2)addWorker方法
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
/**
走出該死循環並繼續執行該方法之後代碼條件是:小於核心線程數或者大於核心線程數與阻塞數之和,或者核心線程未開啓
*/
for (;;) {
…… //代碼省略
}
……
try {
w = new Worker(firstTask); //創建線程,將該工作任務綁定到該線程
final Thread t = w.thread;
if (t != null) {
……
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w); //將創建的線程存入線程隊列裏
……
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start(); //開啓線程
workerStarted = true;
}
}
} …….
return workerStarted;
}
(3)Worker 類
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this); //創建線程
}
(4)當線程啓動時會執行Worker 類中的run方法
public void run() {
runWorker(this); //繼續跟蹤該方法
}
(5)runWorker方法
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//首先執行該線程綁定的任務。而getTask()方法是有關核心線程如何回收重用的,
while (task != null || (task = getTask()) != null) {
……
} finally {
processWorkerExit(w, completedAbruptly);
}
}
(6)getTask()方法
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
//該循環是死循環,當爲核心線程時,隊列爲空,則一直循環,不爲空則返回給runWorker(Worker w) 中的while循環,當非核心線程,則存活到keepAliveTime時間,會跳出該循環,同時也滿足退出runWorker(Worker w) 中的while循環,所以該線程結束生命週期。
for (;;) {
……
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : //當爲非核心線程,執行該代碼
workQueue.take(); //當爲核心線程執行該行。一直從隊列拿數據,所以外面只要往線程池加隊列,就會立馬執行。所以核心線程一直死循環存在。解釋了核心線程爲什麼能夠被重新利用
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}