ThreadPoolExecutor是Java線程的實現之一。
使用線程池的好處:
降低系統資源消耗,避免創建與銷燬線程帶來的資源消耗。
提高響應速度,任務可以從已經從線程池裏獲取一條線程執行而不必new 一條線程。
方便線程的管理與監控。
線程狀態
狀態說明:
RUNNING 接受新任務和已入隊的任務
SHUTDOWN 不接受新任務但處理已入隊的任務
STOP 不接受新任務,不處理已入隊的任務,會終止正在進行的任務。
TIDYING 所有任務都已經終止了,woker的數量已經爲0, 線程會轉換成tidying狀態,並調用terminated()方法
TERMINATED terminated()方法已經執行完畢。
狀態轉換
RUNNING -> SHUTDOWN 執行了shutdown()
(RUNNING or SHUTDOWN) -> STOP 執行了shutdownNow()
SHUTDOWN -> TIDYING 工作隊列爲空並且線程池工作線程數量爲0
STOP -> TIDYING 線程池工作線程數量爲0
TIDYING -> TERMINATED terminated() 方法執行完畢。
構造函數
corePoolSize:核心線程數量,除非設置allowCoreThreadTimeOut,線程池會一直持有corePoolSize數量的線程。
maximumPoolSize:最大線程數量,線程池能夠允許的最大線程池數量。
keepAliveTime:保持存活的時間,當線程池的線程數量大於corePoolSize,處於空閒狀態的線程超過這個時間就會結束。
unit:keepAliveTime時間單位。
workQueue:工作隊列。
threadFactory:線程工廠。
RejectedExecutionHandler 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.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;
}
execute操作
處理分3個步驟
1如果運行的線程數量少於corePoolSize,就開啓一條新的線程,並將該任務作爲worker的第一個任務。
2 如果能成功的進入任務隊列,那麼會再進行一次檢測看是否需要開啓新的線程執行或者狀態不對移除掉剛入隊的任務並執行拒絕策略。
3如果入隊失敗,那麼我們知道線程池關閉了或者飽和了,執行拒絕策略處理。
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))
reject(command);
}
addWorker
該方法主要的工作是創建一個攜帶任務的Woker到wokers集合,Woker會綁定一條線程,同時這條線程會調用start()方法。由此看出woker就是一條線程。
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
//檢測運行狀態是SHUTDOWN,STOP,TIDYING,TERMINATED 並且只要下面的任何一個條件成立即可返回false
//1:狀態不是SHUTDOWN,例如STOP,TIDYING,TERMINATED那麼不能再添加woker了
//2:狀態是SHUTDOWN,不再接受任務了,firstTask不爲空,也不行
//3:狀態SHUTDOWN,firstTask爲空,工作隊列也爲空,不能再添加woker
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//狀態發生改變,就重試
for (;;) {
int wc = workerCountOf(c);
//線程大於CAPACITY
//添加的是core線程的話,工作線程大於corePoolSize否則maximumPoolSize 的話 也返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//增加wc的數量
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
//狀態發生改變重新循環
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//創建Woker 並且綁定了一條線程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
//只讓一個線程進來,設計到共享變量wokers 和 largestPoolSize變量的修改
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
//如果是運行狀態 或者
//是SHUTDOWN狀態 && 傳入任務爲空
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
//更新下最大線程數量
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
//釋放鎖
mainLock.unlock();
}
//添加成功 調用Thread.start()方法
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
run()方法
worker的run方法調用的是外部類ThreadPoolExecutor的runWorker();
public void run() {
runWorker(this);
}
runWoker()
獲取到傳入woker的任務 和 從阻塞隊列裏面獲取任務執行,任務存在就執行task.run();
如果task爲null,退出循環,調用processWorkerExit線程退出工作,最後run執行完畢,線程銷燬。
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
//unlock說明現在還沒有執行任務,就可以被interrupt,也說明阻塞獲取任務的時候是可以被中斷的
w.unlock();
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
//這裏加鎖啥表示wokerThread 獨佔的執行任務,獲取了鎖那麼就不應該被interrupt
w.lock();
// 如果狀態至少是STOP狀態 進一步確認線程是否interrupted
// 如果沒有再一次確認狀態是否是STOP狀態 && wt沒有被中斷
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
//中斷wokerThrad
wt.interrupt();
try {
beforeExecute(wt, task);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
//wokerThread釋放鎖
w.unlock();
}
}
completedAbruptly = false;
} finally {
//處理woker退出
processWorkerExit(w, completedAbruptly);
}
}