最近看到crossoverJie的一篇文章:一個線程罷工的詭異事件
首先感謝原做者的分享,本身獲益匪淺。而後是回想到本身的一次面試經歷,面試官提問了線程池中的線程出現了異常該怎樣捕獲?會致使什麼樣的問題?html
public class ThreadPoolException { private final static Logger LOGGER = LoggerFactory.getLogger(ThreadPoolException.class); public static void main(String[] args) throws InterruptedException { ExecutorService execute = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); execute.execute(new Runnable() { @Override public void run() { LOGGER.info("=====11======="); } }); TimeUnit.SECONDS.sleep(5); execute.execute(new Run1()); } private static class Run1 implements Runnable { @Override public void run() { int count = 0; while (true) { count++; LOGGER.info("-------222-------------{}", count); if (count == 10) { System.out.println(1 / 0); try { } catch (Exception e) { LOGGER.error("Exception",e); } } if (count == 20) { LOGGER.info("count={}", count); break; } } } } }
上面的代碼是原做者本地調試的一個代碼,這裏我也大體交代下情形:java
這裏直接拋異常了,by zero。看到底層是ThreadPoolExecutor 1149行拋出的。
查看線程dump,發現線程池中的線程此時處於WAITING狀態
面試
在執行1149行代碼因爲拋了異常,因此繼續執行finally中processWorkerExit方法:
併發
processWorkerExit中主要作了兩件事,worker remover和addWorker。線程池中的任務都會被包裝爲一個內部 Worker 對象執行。不清楚的能夠參考:Java併發之線程池ThreadPoolExecutor源碼學習
ide
最後會執行addWorker,緊接着咱們繼續往addWorker中去跟,看看裏面作了什麼操做:
學習
addWorker裏面是從新new Worker(), 而後執行worker.start(), 接着咱們看下Worker中的start方法:
線程
由於Woker是實現Runnable接口的,因此會執行其run方法,接着往runWorker方法跟蹤:
調試
由於此時的Worker是上一步從新new出來的,因此其中的task爲空,這時須要繼續跟蹤getTask()方法:
code
此時由於線程池的隊列中並無任務,因此這裏執行take會一直阻塞,也就有了最開始的那個WAITING的狀態了。
到了這裏一切都很明瞭了,源碼面前任何妖魔鬼怪都沒法藏匿,因此但咱們使用線程池的時候必定要注意一異常的捕獲和處理。
下一章來詳細解讀一下如何捕獲線程池中的異常。htm
因爲本人水平有限,文章中若是有不嚴謹的地方還請提出來,願聞其詳。