上一篇文章講了有關線程池的一些簡單的用法,這篇文章主要是從源碼的角度進一步帶你們瞭解線程池的工做流程和工做原理。java
首先先來回顧下如何使用線程池開啓線程多線程
private static void createThreadByThreadPoolExecutor() { ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 10; i++) { MyThread myThread = new MyThread(); executor.execute(myThread); }
能夠看到其實沒有其它特殊的地方,除了構建線程池的代碼,其它最終要的就是executor.execute(myThread)
行代碼了。函數
在多線程系列的第一篇文章中提到了線程和進程的狀態,線程池一樣也有狀態,以下:spa
terminated()
函數terminated()
函數調用完後就進入了此狀態首先須要知道4個概念,Worker
、workers
、workQueue
和 task
.線程
在線程池中有個比較重要的類,那就是Worker
,能夠看到其實現了Runnable
接口(其實就是工做線程),繼承了AbstractQueuedSynchronizer
類(俗稱AQS
,在多線程中是很重要的類)code
workers
就是Worker
的一個集合,private final HashSet<Worker> workers = new HashSet<Worker>();
task
:須要執行的任務,也就是execute()
中的參數,實現了Runnable
接口workQueue
就是工做隊列,就是上一篇文章中線程池構造函數中的工做隊列,裏面存儲的就是須要執行的任務,隊列是實現BlockingQueue
接口的類,有如下這些實現對象
execute()
本方法傳進去的類是須要實現Runnable接口的,做爲一個command
傳進去繼承
遇到新的任務後接口
若是線程池是正常的工做狀態,而且工做隊列可以添加任務,此時須要第二輪判斷隊列
注意:核心線程和非核心線程只是語義上的說法, 沒有本質上的區別
addworker()
addworker
的做用是檢查是否能夠根據當前池狀態和給定界限(核心或最大值)添加新線程 ,而且經過第二個參數來斷定是否建立核心線程,當爲true的時候就是核心線程,反之就是非核心線程。源碼裏的註釋以下
來看看代碼具體是如何的
一進來就是一個死循環,這個死循環最主要的目的是確認線程池狀態是否正常。若是線程池的狀態大於SHUTDOWN,也就是處於STOP、TIDYING或者TERMINATED的時候,線程池都沒了,還建立worker幹啥,直接返回fasle;當線程池處於SHUTDOWN的時候,又得再次判斷:
先來看正常的邏輯,拿到鎖,而且開始又一次的獲取線程池的狀態
alive
那麼而說明線程已經開啓,直接拋出異常。t.start()
addWorkerFailed()
邏輯。整個的邏輯是比較簡單的,就再也不花費篇幅去闡述。到這裏,整個addWorker()
的流程是比較清晰的,值得一提的就是第2行代碼中的retry
這個看起來是關鍵字,但其實不是,僅僅只是一個相似標誌位的東西,能夠是retry,也能夠是abc。
一般是配合for循環來使用,搭配continue和break能夠達到goto的效果。好比continue retry;
就是跳到一開始最外層的for循環,break retry;
至關於退出整個循環。寫一個最簡單的例子你們都能知道了。
public class RetryExample { public static void main(String[] args) { abc: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (j == 2) { continue abc; } if (i == 8) { break abc; } System.out.println("i: " + i + ", j: " + j); } } } }
輸出結果以下圖所示
創做不易,若是對你有幫助,歡迎點贊,收藏和分享啦!
下面是我的公衆號,有興趣的能夠關注一下,說不定就是你的寶藏公衆號哦,基本2,3天1更技術文章!!!