ThreadPoolExecutor 它是線程池最核心的類, 這裡對核心的方法做簡要的剖析(會持續更新),以加深對線程池運行原理的理解。 1. 核心成員變數及相關方法 1 // ctl非常重要,用整型表示,共32位,其中**高3位代表線程池狀態,低29位代表工作線程數**; 2 // 線程池狀態初始 ...
ThreadPoolExecutor 它是線程池最核心的類, 這裡對核心的方法做簡要的剖析(會持續更新),以加深對線程池運行原理的理解。 1. 核心成員變數及相關方法
1 // ctl非常重要,用整型表示,共32位,其中**高3位代表線程池狀態,低29位代表工作線程數**; 2 // 線程池狀態初始化為RUNNING,工作線程數為0 3 private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 4 5 // 偏移量29 6 private static final int COUNT_BITS = Integer.SIZE - 3; 7 8 // 理論最大線程數(約500萬) 9 private static final int CAPACITY = (1 << COUNT_BITS) - 1; 10 11 // -1左偏移29位(下同),運行中狀態,既能接收新提交的任務,又能執行阻塞隊列中的任務 12 private static final int RUNNING = -1 << COUNT_BITS; 13 14 // 關閉狀態,不再接收新提交的任務,但還能繼續執行阻塞隊列中的任務(調用shutdown()可以進入此狀態) 15 private static final int SHUTDOWN = 0 << COUNT_BITS; 16 17 // 停止狀態,不再接收新提交的任務,也不再執行隊列中的任務;而且會嘗試中斷正在執行的工作線程(調用shutdownNow()可以進入此狀態) 18 private static final int STOP = 1 << COUNT_BITS; 19 20 // 清理狀態,當workCount(工作線程數)為0,且隊列也為空時就是此狀態 21 // SHUTDOWN -> TIDYING 線程數為0,隊列也為空時會自動進入改狀態 22 // STOP -> TIDYING 線程數為0時,就會自動進入該狀態 23 private static final int TIDYING = 2 << COUNT_BITS; 24 25 // 終結狀態 可以通過調用awaitTermination方法來來等待線程池徹底終結 26 private static final int TERMINATED = 3 << COUNT_BITS; 27 28 // 獲取線程池運行狀態;因為CAPACITY為29個1,取反後是29個0,再通過&運算會取出最高的3位 29 private static int runStateOf(int c) { return c & ~CAPACITY; } 30 31 // 獲取線程池中線程數;取出最低的29位 32 private static int workerCountOf(int c) { return c & CAPACITY; } 33 34 // 將運行狀態與線程數拼接起來,共有恰好有32位(因為rs已經左偏移29位了!) 35 private static int ctlOf(int rs, int wc) { return rs | wc; }
2. 核心構造方法
1 /* 2 * 1. 共有7個參數 3 * 2. 具體實現不再細說,只簡單說下各個作用(就是使用流程) 4 * corePoolSize: 核心線程數,如果總工作線程數小於核心線程數, 有新任務時則會繼續創建新的線程 5 * maximumPoolSize: 最大線程數,理論上包含了核心線程數和非核心線程數 6 * keepAliveTime: 一般上(allowCoreThreadTimeOut=false)是指非核心線程沒有任務執行的存活時間(可以通過getTask()方法去分析) 7 * TimeUnit: keepAliveTime的時間單位 8 * workQueue: 阻塞隊列,其中包含有SynchronousQueue, ArrayBlockingQueue, LinkedBlockingQueue; 存放核心線程執行不過來時被提交的任務 9 * threadFactory: 線程工廠,創建線程的地方 10 * handler: 拒絕策略,線程池滿時會執行該策略rejectedExecution()方法;自帶有4種拒絕策略,預設使用拋異常拒絕策略,另有什麼都不做策略,用調用者線程執行任務策略,拋棄最舊任務策略 11 * 12 * 註意:1. 核心線程和非核心線程只是個邏輯的概念,某個線程被創建後,一開始可能是核心的,到後來會變成非核心的,身份並不固定。(看具體getTask()時會不會得到null) 13 * 2. 流程歸總:當新任務被提交後,當工作線程數小於核心核心線程數時,會繼續創建線程來處理此任務,否則會將其放在阻塞隊列中;若阻塞隊列已滿,則會創建線程來處理此任務;若創建線程失敗(不小於了最大線程數),則會執行拒絕策略。 14 */ 15 public ThreadPoolExecutor(int corePoolSize, 16 int maximumPoolSize, 17 long keepAliveTime, 18 TimeUnit unit, 19 BlockingQueue<Runnable> workQueue, 20 ThreadFactory threadFactory, 21 RejectedExecutionHandler handler) { 22 if (corePoolSize < 0 || 23 maximumPoolSize <= 0 || 24 maximumPoolSize < corePoolSize || 25 keepAliveTime < 0) 26 throw new IllegalArgumentException(); 27 if (workQueue == null || threadFactory == null || handler == null) 28 throw new NullPointerException(); 29 this.acc = System.getSecurityManager() == null ? 30 null : 31 AccessController.getContext(); 32 this.corePoolSize = corePoolSize; 33 this.maximumPoolSize = maximumPoolSize; 34 this.workQueue = workQueue; 35 this.keepAliveTime = unit.toNanos(keepAliveTime); 36 this.threadFactory = threadFactory; 37 this.handler = handler; 38 }
3. 疑問
1. 線程池屬於terminated後,是怎麼樣釋放資源的?terminated()方法是空實現? 2. execute()添加到隊列後為什麼還要recheck?