當調用 execute() 方法添加一個任務時,線程池會做如下判斷:
a. 如果正在運行的線程數量小於 corePoolSize,那麼馬上創建線程運行這個任務;
b. 如果正在運行的線程數量大於或等於 corePoolSize,那麼將這個任務放入隊列。
c. 如果這時候隊列滿了,而且正在運行的線程數量小於 maximumPoolSize,那麼還是要創建線程運行這個任務;
d. 如果隊列滿了,而且正在運行的線程數量大於或等於 maximumPoolSize,那麼線程池會拋出異常,告訴調用者“我不能再接受任務了”。
e.當一個線程完成任務時,它會從隊列中取下一個任務來執行。
f.當一個線程無事可做,超過一定的時間(keepAliveTime)時,線程池會判斷,如果當前運行的線程數大於 corePoolSize,那麼這個線程就被停掉。所以線程池的所有任務完成後,它最終會收縮到 corePoolSize 的大小。
一:Executor 將有限邊界用於最大線程和工作隊列容量飽和:
- 在
ThreadPoolExecutor.AbortPolicy
中,處理程序遭到拒絕將拋出運行時RejectedExecutionException
。 - 在
ThreadPoolExecutor.CallerRunsPolicy
中,線程調用運行該任務的execute
本身。此策略提供簡單的反饋控制機制,能夠減緩新任務的提交速度。 - 在
ThreadPoolExecutor.DiscardPolicy
中,不能執行的任務將被刪除,不拋出異常。 - 在
ThreadPoolExecutor.DiscardOldestPolicy
中,如果執行程序尚未關閉,則位於工作隊列頭部的任務將被刪除,然後重試執行程序(如果再次失敗,則重複此過程)。不拋出異常。
public class LufaxThreadFactory implements ThreadFactory {
private static final ThreadFactory DEFAULT_THREAD_FACTORY = Executors.defaultThreadFactory();
public LufaxThreadFactory(String module) {
this.module = module;
}
@Override
public Thread newThread(Runnable r) {
if (r == null) throw new NullPointerException();
Thread t = DEFAULT_THREAD_FACTORY.newThread(r);
//設置捕獲異常
t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
Logger.error(this, String.format("Failed to exeute runnable r [module:%s]", module), e);
}
});
return t;
}}
2)executorService.execute(Callable<T> callable) Future.get()會拋出ExecutionException
線程池 java.util.concurrent.ThreadPoolExecutor
會Catch住所有異常, 當任務執行完成(java.util.concurrent.ExecutorService.submit(Callable))獲取其結果 時(java.util.concurrent.Future.get())會拋出此RuntimeException。
V innerGet() throws InterruptedException, ExecutionException {
acquireSharedInterruptibly(0);
if (getState() == CANCELLED)
throw new CancellationException();
if (exception != null)
throw new ExecutionException(exception);
return result;
}
三:鉤子回調 beforeExecute()和afterExecute() 監控線程
也就是說當我們想線程池 ThreadPoolExecutor(java.util.concurrent.ExecutorService)提交任務時, 如果不理會任務結果(Feture.get()),那麼此異常將被線程池吃掉。
privatevolatileint corePoolSize; //都是volatile變量
ExecutorService service = Executors.newFixedThreadPool(3);//底層ThreadPoolExecutor
publicclass ThreadPoolExecutor extends AbstractExecutorService{}
publicstatic ExecutorService newFixedThreadPool(int nThreads) {
returnnew ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
publicvoid execute(Runnable command) {
if (command == null)
thrownew NullPointerException();
//poolSize大於等於corePoolSize時不增加線程,反之(poolSize < corePoolSize)新初始化線程
if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
//線程執行狀態外爲執行,同時可以添加到隊列中
if (runState == RUNNING && workQueue.offer(command)) { //入隊列
if (runState != RUNNING || poolSize == 0)
ensureQueuedTaskHandled(command);
}
elseif (!addIfUnderMaximumPoolSize(command))//隊列已滿,並且未達到MaxPoolSize繼續啓動線程
reject(command); // is shutdown or saturated
}
}
privateboolean addIfUnderCorePoolSize(Runnable firstTask) {
Thread t = null;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (poolSize < corePoolSize && runState == RUNNING)
t = addThread(firstTask);
} finally {
mainLock.unlock();
}
if (t == null)
returnfalse;
t.start(); //啓動線程
returntrue;
}
private Thread addThread(Runnable firstTask) {
Worker w = new Worker(firstTask); //Worker包裝Runnable
Thread t = threadFactory.newThread(w); //生成線程對象Thread
if (t != null) {
w.thread = t;
workers.add(w);
int nt = ++poolSize;
if (nt > largestPoolSize)
largestPoolSize = nt;
}
return t;
}
privatefinalclass Worker implements Runnable {
/**
* The runLock is acquired and released surrounding each task
* execution. It mainly protects against interrupts that are
* intended to cancel the worker thread from instead
* interrupting the task being run.
*/
privatefinal ReentrantLock runLock = new ReentrantLock();
/**
* Initial task to run before entering run loop. Possibly null.
*/
private Runnable firstTask;
/**
* Per thread completed task counter; accumulated
* into completedTaskCount upon termination.
*/
volatilelongcompletedTasks;
/**
* Thread this worker is running in. Acts as a final field,
* but cannot be set until thread is created.
*/
Thread thread;
Worker(Runnable firstTask) {
this.firstTask = firstTask;
}
/**
* Runs a single task between before/after methods.
*/
privatevoidrunTask(Runnable task) {
final ReentrantLock runLock = this.runLock;
runLock.lock();
try {
/*
* Ensure that unless pool is stopping, this thread
* does not have its interrupt set. This requires a
* double-check of state in case the interrupt was
* cleared concurrently with a shutdownNow -- if so,
* the interrupt is re-enabled.
*/
//當線程池的執行狀態爲關閉等,則執行當前線程的interrupt()操作
if (runState < STOP &&
Thread.interrupted() &&
runState >= STOP)
thread.interrupt();
/*
* Track execution state to ensure that afterExecute
* is called only if task completed or threw
* exception. Otherwise, the caught runtime exception
* will have been thrown by afterExecute itself, in
* which case we don't want to call it again.
*/
boolean ran = false;
beforeExecute(thread, task);
try {
task.run();
ran = true;
afterExecute(task, null);
++completedTasks;
} catch (RuntimeException ex) {
if (!ran)
afterExecute(task, ex);
throw ex;
}
} finally {
runLock.unlock();
}
}
/**
* Main run loop
*/
publicvoid run() {
try {
Runnable task = firstTask;
firstTask = null;
//判斷是否存在需要執行的任務
while (task != null || (task = getTask()) != null) {
runTask(task);
task = null;
}
} finally {
//如果沒有,則將工作線程移除,當poolSize爲0是則嘗試關閉線程池
workerDone(this);
}
}
}
/* Utilities for worker thread control */
/**
* Gets the next task for a worker thread to run. The general
* approach is similar to execute() in that worker threads trying
* to get a task to run do so on the basis of prevailing state
* accessed outside of locks. This may cause them to choose the
* "wrong" action, such as trying to exit because no tasks
* appear to be available, or entering a take when the pool is in
* the process of being shut down. These potential problems are
* countered by (1) rechecking pool state (in workerCanExit)
* before giving up, and (2) interrupting other workers upon
* shutdown, so they can recheck state. All other user-based state
* changes (to allowCoreThreadTimeOut etc) are OK even when
* performed asynchronously wrt getTask.
*
* @return the task
*/
Runnable getTask() {
for (;;) {
try {
int state = runState;
if (state > SHUTDOWN)
returnnull;
Runnable r;
if (state == SHUTDOWN) // Help drain queue
r = workQueue.poll();
//當線程池大於corePoolSize,同時,存在執行超時時間,則等待相應時間,拿出隊列中的線程
elseif (poolSize > corePoolSize || allowCoreThreadTimeOut)
r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
else
//阻塞等待隊列中可以取到新線程
r = workQueue.take();
if (r != null)
return r;
//判斷線程池運行狀態,如果大於corePoolSize,或者線程隊列爲空,也或者線程池爲終止的工作線程可以銷燬
if (workerCanExit()) {
if (runState >= SHUTDOWN) // Wake up others
interruptIdleWorkers();
returnnull;
}
// Else retry
} catch (InterruptedException ie) {
// On interruption, re-check runState
}
}
}
/**
* Performs bookkeeping for an exiting worker thread.
* @param w the worker
*/
//記錄執行任務數量,將工作線程移除,當poolSize爲0是則嘗試關閉線程池
void workerDone(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
if (--poolSize == 0)
tryTerminate();
} finally {
mainLock.unlock();
}
}