public static void main(String[] args) throws Exception{
int corePoolSize = 5;
int maximumPoolSize = 10;
int blockingQueueSize = 13;
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
corePoolSize, //最小線程數
maximumPoolSize, //最大線程數
100, TimeUnit.MILLISECONDS, //超過最小線程數的線程,空閒多久則回收
new ArrayBlockingQueue<>(blockingQueueSize, true)//放到某個隊列裏
);
//是否去掉非活動線程
threadPoolExecutor.allowCoreThreadTimeOut(true);
//默認創建最小線程數的線程
threadPoolExecutor.prestartAllCoreThreads();
Set<Long> threadId = new HashSet<>();
long threadsStartTime = System.currentTimeMillis();
for (int i = 0; i < 20; i++) {
threadPoolExecutor.execute(() -> {
try {
long threadStartTime = System.currentTimeMillis();
Thread thread = Thread.currentThread();
long id = thread.getId();
long subTime = threadStartTime - threadsStartTime;
System.out.println("threadsStartTime:"+threadsStartTime+",threadStartTime:"+threadStartTime+",subTime:"+ subTime +",id:"+id);
Thread.sleep(3000);
if(threadId.contains(id)){
System.out.println("已存在的線程執行任務:"+id +":"+thread.getName());
}else{
threadId.add(id);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
System.in.read();
}
測試
- 創建20個任務,阻塞隊列長度爲18,線程池最小線程數爲5,最大線程數爲10
從上圖可知,線程池創建了5個線程處理了5個任務,15個任務扔進了隊列
- 創建20個任務,阻塞隊列長度爲13,線程池最小線程數爲5,最大線程數爲10
從上圖可知,線程池創建了7個線程處理了7個任務,13個任務扔進了隊列 - 創建20個任務,阻塞隊列長度爲9,線程池最小線程數爲5,最大線程數爲10
從上圖可知,線程池創建了10個線程處理了10個任務,9個任務扔進了隊列,一個任務被拒絕
源碼分析
基於測試結果,應該對其執行過程有了初步的瞭解
execute(Runnable command)
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
//如果線程池中線程數沒有達到corePoolSize,則新增線程(worker)
if (addWorker(command, true))
return;
//更新c值。
c = ctl.get();
}
//線程池處於RUNNING狀態,並且阻塞隊列未滿
//workQueue.offer(command)是非阻塞方法,當隊列滿時直接返回false(例如,SynchronousQueue如果沒有線程在阻塞take,則返回false)
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//再次檢查狀態,如果發現不是RUNNING狀態,則remove掉剛纔offer的任務。
if (! isRunning(recheck) && remove(command))
reject(command);
//如果有效線程數==0,添加一個線程,而不去啓動它。??
//怎麼會==0?
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果不是RUNNING狀態,或者阻塞隊列已滿,則添加線程
//如果不能添加,則reject。
//false 表示添加的線程屬於maximumPoolSize,如果線程數已經達到maximumPoolSize,則reject
else if (!addWorker(command, false))
reject(command);
}
阻塞隊列(BlockingQueue) 的一些操作方法
* | 拋出異常 | 特殊值 | 阻塞 | 超時 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e, time, unit) |
移除 | remove() | poll() | take() | poll(time, unit) |
檢查 | element() | peek() | 不可用 | 不可用 |
addWorker(Runnable firstTask, boolean core)
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
//1. 處於 STOP, TYDING 或 TERMINATD 狀態 並且
//2. 不是SUHTDOWN 或者 firsttask != null 或 queue不爲空
return false;
for (;;) {
int wc = workerCountOf(c);
//wc大於最大容量。
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
//沒有空餘的線程了。
return false;
//有效線程數加一,加一成功後break
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
//runState改變,從頭執行邏輯。
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
//else runState 沒變,重新去執行加一操作。
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
//創建worker
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
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();
}
if (workerAdded) {
//添加成功,啓動線程
//啓動後執行runWorker(this);
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker(Worker w)
運行worker,該線程不斷的getTask()從隊列中獲取任務,然後 task.run();運行。只要隊列中有值則不斷循環。
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()方法是個無限循環, 會從阻塞隊列 workQueue中不斷取出任務來執行.
//addWorker(null, false);情況,task==null,這樣就需要getTask從隊列中取任務執行(自己不帶任務)。直到getTask返回null
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
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++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
getTask()
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
// STOP以上狀態,或者SHUTDOWN狀態下queue爲空,即都沒有任務要執行了。
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//線程數減一
decrementWorkerCount();
//該線程退出。
return null;
}
//下面都是RUNNING狀態,或SHUTDOWN狀態queue!=null
int wc = workerCountOf(c);
// Are workers subject to culling?
//設置了allowCoreThreadTimeOut,或者線程數大於core線程數。
//是否剔除超時的線程?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
// 通過返回 null 結束線程。
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
//線程已經準備好,正在take(),沒有什麼標誌位?
//取出runnable 返回
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
結論
線程池執行任務流程
- 當線程數小於線程池的最小線程數時,會創建線程去執行任務
- 當線程池的線程數大於等於線程池的最小線程數時,如果線程池處於運行狀態,且阻塞隊列沒滿時,則將任務塞進隊列
- 如果隊列滿時,但線程池的線程數小於最大線程數時,直接創建線程去處理任務
- 否則拒絕任務