ThreadPoolExecutor 線程銷燬源碼分析

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"線程池在開發中使用非常頻繁,在面試中也是高頻面試點,最近翻看源碼,有一些心得分享下:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"線程池回收線程的大致流程:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1、調用線程池的 shutdown() 方法或者 shutdownNow() 方法;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2、主線程修改線程池的狀態:","attrs":{}}]},{"type":"paragraph","attrs":{"indent":1,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"shutdown() -> SHUTDOWN","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" shutdownNow() -> STOP","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3、中斷線程池中所有線程;中斷一些阻塞的線程,讓線程正常結束執行;","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"4、每個 work 線程在獲取任務的時候 getTask(), 校驗當前線程池的狀態,如果線程池狀態已經被修改爲非 RUNNING狀態,時機合適,work線程退出","attrs":{}},{"type":"text","text":";","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"詳情請看下面的源碼註釋:","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. 線程池狀態:","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"// 線程池初始狀態\nprivate static final int RUNNING = -1 << COUNT_BITS;\n// 調用 shutdown() 方法後線程池狀態\nprivate static final int SHUTDOWN = 0 << COUNT_BITS;\n// 調用 shutdownNow() 方法後線程池狀態\nprivate static final int STOP = 1 << COUNT_BITS;\n// 在 TERMINATED 前的一個過渡狀態,用處不多\nprivate static final int TIDYING = 2 << COUNT_BITS;\n// 線程池終止狀態\nprivate static final int TERMINATED = 3 << COUNT_BITS;","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.1 shutdown 方法","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public void shutdown() {\n final ReentrantLock mainLock = this.mainLock;\n mainLock.lock();\n try {\n // 校驗調用 shutdown() 線程是否可以操作此方法,校驗被終止任務的線程(works)是否可以被終止\n checkShutdownAccess();\n // CAS 修改線程池運行狀態爲:SHUTDOWN \n advanceRunState(SHUTDOWN);\n // 中斷所有工作線程\n interruptIdleWorkers();\n // hook for ScheduledThreadPoolExecutor\n onShutdown(); \n } finally {\n mainLock.unlock();\n }\n \t// 嘗試中斷線程池\n tryTerminate();\n}","attrs":{}}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2.2 shutdownNow","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"public List shutdownNow() {\n List tasks;\n final ReentrantLock mainLock = this.mainLock;\n mainLock.lock();\n try {\n // 校驗調用 shutdownNow() 線程是否可以操作此方法,校驗被終止任務的線程(works)是否可以被終止\n checkShutdownAccess();\n // CAS 修改線程池運行狀態爲:STOP \n advanceRunState(STOP);\n // 中斷所有工作線程\n interruptWorkers();\n // 移除隊列中的任務,並返回被移除的任務\n tasks = drainQueue();\n } finally {\n mainLock.unlock();\n }\n tryTerminate();\n return tasks;\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3. interruptIdleWorkers","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void interruptIdleWorkers(boolean onlyOne) {\n final ReentrantLock mainLock = this.mainLock;\n mainLock.lock();\n try {\n // 遍歷 works 工作線程集合,中斷每個阻塞獲取任務的線程,讓這些線程執行完當前邏輯,退出 run() 方法\n for (Worker w : workers) {\n Thread t = w.thread;\n if (!t.isInterrupted() && w.tryLock()) {\n try {\n t.interrupt();\n } catch (SecurityException ignore) {\n } finally {\n w.unlock();\n }\n }\n if (onlyOne)\n break;\n }\n } finally {\n mainLock.unlock();\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4. tryTerminate()","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" final void tryTerminate() {\n for (;;) {\n int c = ctl.get();\n // 線程池 RUNNING 退出\n // 線程池 TIDYING 退出\n // 線程池 SHUTDOWN 並且 隊列不爲空(還有沒處理完的任務)退出\n if (isRunning(c) ||\n runStateAtLeast(c, TIDYING) ||\n (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))\n return;\n // 還有活躍的線程,中斷一個\n if (workerCountOf(c) != 0) { // Eligible to terminate\n interruptIdleWorkers(ONLY_ONE);\n return;\n }\n\n final ReentrantLock mainLock = this.mainLock;\n mainLock.lock();\n try {\n if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {\n try {\n terminated();\n } finally {\n ctl.set(ctlOf(TERMINATED, 0));\n termination.signalAll();\n }\n return;\n }\n } finally {\n mainLock.unlock();\n }\n // else retry on failed CAS\n }\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"5.Work 類:工作線程","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":" private final class Worker extends AbstractQueuedSynchronizer implements Runnable{\n private static final long serialVersionUID = 6138294804551838833L;\n\n /** 線程池裏的工作線程,該線程在創建 Work 對象的時候傳入 */\n final Thread thread;\n /** 工作線程創建好後,執行的第一個任務 */\n Runnable firstTask;\n /** 工作線程執行任務數量 */\n volatile long completedTasks;\n\n /**\n * 創建一個Work線程,指定第一個被執行的任務\n */\n Worker(Runnable firstTask) {\n setState(-1); \n this.firstTask = firstTask;\n this.thread = getThreadFactory().newThread(this);\n }\n\n /** work 線程啓動後,執行run方法,直到線程退出 */\n public void run() {\n runWorker(this);\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"6. runWorker","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"final void runWorker(Worker w) {\n Thread wt = Thread.currentThread();\n // task 默認爲創建work時候指定的第一個任務\n Runnable task = w.firstTask;\n w.firstTask = null;\n w.unlock(); // allow interrupts\n boolean completedAbruptly = true;\n try {\n \n /**\n * 1、第一個任務不爲 null,先執行第一個任務,往後循環的從任務隊列裏取任務執行\n * 2、只有 getTask() 返回null的時候,纔會退出循環\n */\n while (task != null || (task = getTask()) != null) {\n w.lock();\n /** double check\n * 防止線程池已經被設置成 STOP 狀態後,部分線程響應中斷失敗,\n * 這個地方再重新校驗並設置下當前線程的中斷狀態\n */\n if ((runStateAtLeast(ctl.get(), STOP) ||\n (Thread.interrupted() &&\n runStateAtLeast(ctl.get(), STOP))) &&\n !wt.isInterrupted())\n wt.interrupt();\n try {\n // 默認沒有實現,可以在子類中擴展\n beforeExecute(wt, task);\n Throwable thrown = null;\n // 執行任務\n task.run();\n // 省略部分 try-catch 代碼\n } finally {\n task = null;\n // 當前線程執行任務數累計\n w.completedTasks++;\n w.unlock();\n }\n }\n // 當 getTask() 爲null的時候可以走到這一步\n completedAbruptly = false;\n } finally {\n // getTask() 爲 null,任務被執行完了,線程退出\n processWorkerExit(w, completedAbruptly);\n }","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","marks":[{"type":"color","attrs":{"color":"#F5222D","name":"red"}}],"text":"7. getTask","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private Runnable getTask() {\n // 記錄上次從任務隊列獲取任務是否超時\n boolean timedOut = false; \n // 循環遍歷,直到獲取到任務或者被中斷\n for (;;) {\n // 線程池線程數量\n int c = ctl.get();\n // 線程池狀態\n int rs = runStateOf(c);\n\t\t\n // 如果線程池狀態:RUNNING(-1)|SHUTDOWN(0)|STOP(1)|TIDYING(2)|TERMINATED(3)\n // 兩種情況:\n // 1、如果是 STOP 以後狀態(不用管任務隊列裏是否有任務未執行完),線程總數減1,立即返回 null;\n // 2、在上面的情況之後,如果是 SHUTDOWN 以後的狀態 && 任務隊列爲空(因爲要等任務執行完),線程總數減1,並立即返回 null;\n if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {\n decrementWorkerCount();\n return null;\n }\n int wc = workerCountOf(c);\n /**\n * 1、allowCoreThreadTimeOut:是否讓核心線程空閒回收,默認false\n * 2、當前線程池中線程數是否大於核心線程數\n */\n boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;\n\t\t\n /** \n * 在線程池中'還有線程'或者'任務隊列沒有任務'的情況下:\n * 1、如果線程池中的線程數,大於設置的最大線程數,必須停止當前線程;\n * 2、在當前線程獲取任務超時(說明隊列裏沒有任務可以被執行):\n * (1)而核心線程允許超時回收,則回收當前線程(因爲核心線程和線程池中其他線程沒有特殊的標記,\n * 回收了就回收了,如果下次線程池中線程不足,再新建一個線程扮演核心線程的角色即可);\n * (2) 當前線程總數超過了核心線程數,而現在又沒有任務需要執行,自然回收當前線程;\n */\n if ((wc > maximumPoolSize || (timed && timedOut))\n && (wc > 1 || workQueue.isEmpty())) {\n if (compareAndDecrementWorkerCount(c))\n return null;\n continue;\n }\n try {\n /** \n * 1、如果允許核心線程空閒退出 或者 當前線程數大於核心線程數的情況下:\n * \t\tpoll() 設置獲取任務的阻塞時間,超時後,返回 null,當循環執行到上面的兩處校驗處,返回 null 退出;\n * 2、take()阻塞式獲取任務,知道任務隊列有可被執行任務爲止;\n */\n Runnable r = timed ?\n workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :\n workQueue.take();\n if (r != null)\n return r;\n // 超時後仍未獲取到任務\n timedOut = true;\n } catch (InterruptedException retry) {\n timedOut = false;\n }\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"8. processWorkerExit","attrs":{}}]},{"type":"codeblock","attrs":{"lang":"java"},"content":[{"type":"text","text":"private void processWorkerExit(Worker w, boolean completedAbruptly) {\n if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted\n decrementWorkerCount();\n final ReentrantLock mainLock = this.mainLock;\n mainLock.lock();\n try {\n // 統計每個線程完成的任務數\n completedTaskCount += w.completedTasks;\n // 從線程池(set)中移除當前線程\n workers.remove(w);\n } finally {\n mainLock.unlock();\n }\n\t// 修改線程池中斷狀態\n tryTerminate();\n\n int c = ctl.get();\n /**\n * 如果當前線程池的狀態不是 STOP,說明當前狀態是 RUNNING 或者 SHUTDOWN,\n * 這個時候要保證線程池內有必要的線程去執行隊列的任務\n */\n if (runStateLessThan(c, STOP)) {\n if (!completedAbruptly) {\n int min = allowCoreThreadTimeOut ? 0 : corePoolSize;\n // 如果當前線程數爲0,但是任務隊列裏又有任務需要被執行,必須調整線程數\n if (min == 0 && ! workQueue.isEmpty())\n min = 1;\n if (workerCountOf(c) >= min)\n return; // replacement not needed\n }\n // 給線程池新增一個線程,保證任務被執行完\n addWorker(null, false);\n }\n}","attrs":{}}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章