用過java線程的同學都應該大致了解,在java中,為了合理使用線程以合理利用資源、提高吞吐率以及加快響應時間,通常會使用java線程池,因為線程池架構設計合理,比起自己創建線程可能花銷巨大來講,線程池是一個很好的選擇。
作為一只喜歡研究源碼的程序猿,就我所學,來講講java線程池是如何鞏工作的。
一.4種線程池
首先,java線程池為我們量身定制了4中拿來即用的線程池:
1.newSingleThreadExecutor:
public static ExecutorServicenewSingleThreadExecutor() {
????????????return new FinalizableDelegatedExecutorService
? ? ? ?????????????(new ThreadPoolExecutor(1, 1,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0L, TimeUnit.MILLISECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue()));
}
2.newFixedThreadPool:
public static ExecutorServicenewFixedThreadPool(int nThreads) {
????????????return new ThreadPoolExecutor(nThreads, nThreads,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 0L, TimeUnit.MILLISECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new LinkedBlockingQueue());
}
3.newCachedThreadPool:
public static ExecutorServicenewCachedThreadPool() {
????????????return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 60L, TimeUnit.SECONDS,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? new SynchronousQueue());
}
4. newScheduledThreadPool:
public static ScheduledExecutorServicenewSingleThreadScheduledExecutor() {
????????????return new DelegatedScheduledExecutorService
????????????????????????(new ScheduledThreadPoolExecutor(1));
}
可以發現:除了newScheduledThreadPool,其他三個都是ThreadPoolExecutor的一種特殊實現。
二.ThreadPoolExecutor
public ThreadPoolExecutor(int corePoolSize,
? ? ? ? ? ? ? ? ? ? ? ? ? int maximumPoolSize,
? ? ? ? ? ? ? ? ? ? ? ? ? long keepAliveTime,
? ? ? ? ? ? ? ? ? ? ? ? ? TimeUnit unit,
? ? ? ? ? ? ? ? ? ? ? ? ? BlockingQueue 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;
}
1.構造函數參數說明:
1).corePoolSize:線程池中的核心線程數
2).maximumPoolSize:線程池中的最大線程數
3).keepAliveTime: 線程池中的線程的存活時間
4).unit: keepAliveTime的時間單位
5).workQueue: BlockingQueue的實現,用于存儲任務
6).threadFactory:自定義線程的創建工廠
7).handler:線程池的飽和策略,當阻塞隊列滿了,且沒有空閑的線程,繼續提交任務時,必須進行處理,默認的方式是拋出RejectedExecutionHandler異常
2.內部狀態變量說明:
jdk1.8就是用一個int型來表示線程池的運行狀態和運行任務數量,一個int一共32位,前3位表示運行狀態,后29位表示運行任務線程數;運行狀態和運行任務線程數量分別通過runStateOf(int c)和workerCountOf(int c)來獲取,都是通過&操作來計算的。各個值的初始值分為如下:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
?1).ctl:包裝任務狀態和線程數(高3位表示運行狀態,后29位表示運行任務線程數),初始值:11100000000000000000000000000000,沒多一線程就加1,為原子操作;默認AtomicInteger,如果數量不夠的話,可以自行改成AtomicLong
? 2).COUNT_BITS:29
? 3).CAPACITY:運行任務線程數,值為:000 11111111111111111111111111111
??4).RUNNING:運行狀態,? ? ? ?值為:111 00000000000000000000000000000
??5).SHUTDOWN:關閉狀態,? 值為:0
? 6).STOP: 停止狀態,? ? ? ? ? ? ?值為:001 00000000000000000000000000000
? 7).TIDYING:整理狀態,? ? ? ? ?值為:010 00000000000000000000000000000
? 8).TERMINATED:終止狀態,值為:011 00000000000000000000000000000
3.內部公用函數說明:
1).runStateOf(int c):獲取運行狀態,
2).workerCountOf(int c):獲取運行任務線程數
3).ctl(int rs,int wc): 包裝運行狀態和任務線程數
4).runStateLessThan(int c,int s):是否小于某個狀態
5).runStateAtLesat(int c,int s):是否大于或者等于某個狀態
這些公共函數接下來都會用到,寫在這里是便于理解。
4.提交任務函數:execute(Runnable command)
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);
}
1).如果當前運行任務線程數小于corePoolSize,嘗試另起線程去運行任務。調用addWorker函數會自動檢查運行狀態和運行任務線程數,防止添加線程時出現多線程操作錯誤。
2).如果添加新的線程失敗,那么就將該任務添加到隊列中,同時,還需要檢查運行狀態和運行任務線程數;再次檢查狀態,防止入列期間出現狀態改變情況,如果線程池處于非運行狀態,移除任務;如果沒有運行任務線程數量為0,則起一個新的線程。
3).如果任務不能進入隊列(例如隊列滿了),再次嘗試另起一個線程運行;如果失敗了,使用拒絕策略。
5.addWorker
在execute函數中,addWorker是另起線程去執行任務,它的具體實現如下:
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()))
????????????????return false;
????????for (;;) {
????????????int wc = workerCountOf(c);
????????????if (wc >= CAPACITY ||?
? ? ? ? ? ? ? ? ? ? wc >= (core ? corePoolSize : maximumPoolSize))
????????????????return false;
????????????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 {
????????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) {
????????????????????t.start();
????????????????????workerStarted = true;
????????????????}
????????????}
????????} finally {
????????????if (! workerStarted)
????????????addWorkerFailed(w);
????????????}
????????????return workerStarted;
}