阻塞隊列模型介紹java
阻塞隊列模型和線程池息息相關,所以本篇博客先介紹阻塞隊列的相關知識。以下圖所示:
數組
首先咱們來講,什麼是Queue,而後在談什麼是BlockingQueue。
緩存
那麼什麼是Queue呢?一句話,就是一端進,另外一端出,這樣就造成了First In , First Out,即先進先出。而BlockingQueue只不過是在Queue的基礎上進行了2個附加操做而已:若是Queue空,那麼Out線程阻塞,若是Queue滿,那麼In線程阻塞。併發
理解了上面的Queue/BlockingQueue,那麼就好理解Deque/BlockingDeque了。ide
Deque,就是雙端隊列,其實就是說在2端,均可以進行IN/OUT,固然若是咱們只在同一端進行IN/OUT,那麼天然造成了棧結構(先進後出)。高併發
其次,咱們先來看看java.util.concurrent.BlockingQueue的API列表:spa
其實從這裏能夠看出JAVA API的一個思路,每每一個操做提供多種選擇:線程
若是隊列是空的,那麼消費線程該如何處理呢?3d
能夠馬上拋出異常,也能夠返回false/NULL,也能夠過一段時間在TRY...blog
好了,到這裏,咱們只看到了接口API,若是要你來實現,你會怎麼作呢?又會有哪些疑問呢?
思考:
是否應該提供一個存儲,來放置隊列中的元素呢?
這個存儲應該多大呢?能夠是什麼形式呢?
隊列中的元素是否存在優先級排序呢?
對隊列中的元素進行操做時,是否應該有鎖的控制呢?
一端IN,另外一端OUT,這2個操做能夠同時進行嗎?
帶着這些疑問,咱們來對典型的BlockingQueue來進行分析。
ArrayBlockingQueue PK LinkedBlockingQueue
存儲PK:
從名稱上就能夠知道,一個用的是數組,另外一個用的是鏈表。看看源碼驗證下:
ArrayBlockingQueue:
LinkedBlockingQueue:
容量PK:
ArrayBlockingQueue能夠經過構造方法指定容量:
而LinkedBlockingQueue若是在初始化時不指定容量,那麼將是Integer.MAX_VALUE,這一點很重要,特別是在生產者的速度大於消費者的速度,因爲此時無容量限制,將致使隊列中的元素開始膨脹,那麼將消耗掉大量系統資源。
鎖PK:
在ArrayBlockingQueue中只有一個鎖:
而在LinkedBlockingQueue中有2個鎖:
其實到這裏,咱們已經能夠大體猜想出,LinkedBlockingQueue對於take/put使用了分別的鎖,從而比ArrayBlockingQueue在高併發下更具優點。
咱們再來看看其餘BlockingQueue:
DelayQueue:延遲隊列,其實是說,隊列中的元素生效的話,有個時間差。
PriorityQueue:優先級隊列,會提供Comparator來進行隊列中的元素的排序。
SynchronousQueue:這個隊列比較特殊,由於沒有存儲機制,實際上只是作了一個生產者和消費者的傳遞機制。
線程池介紹
若是任務到達時,纔開始建立線程,這實際上會讓任務的執行被延遲,因而產生了線程池的概念,若是在池子中已經存在了一批線程,那麼任務到達時天然省去了線程建立的時間,至關於提升了響應速度。其次,若是線程執行完任務後,在放入池子中,這至關於在複用線程,達到了資源節約的目的。固然,若是任務的執行時間是遠遠大於線程的建立/銷燬時間,其實就無所謂了。
快速建立線程池:Executors
Executors提供了一系列的快速建立線程池的方法,好比:
建立數量固定的/單個的/緩存的 線程池。
能夠看到線程池的建立利用到了上面說起的BlockingQueue,隊列中的元素就是任務Runnable。
方法返回的都是ExecutorService的實現類:ThreadPoolExecutor。
線程池的核心:ThreadPoolExecutor
咱們直接來看看ThreadPoolExecutor的構造方法:
理解這些參數,對於理解線程池的原理有很大幫助:
corePoolSize:線程池的核心線程數量,是線程數目的一個穩定峯值。
maximumPoolSize:線程池的最大線程數量,若是corePoolSize依舊知足不了須要,那麼可讓線程增加至maximumPoolSize,一旦須要降低,那麼超出核心線程的那一部分線程資源將被回收。
workQueue:這個隊列是待處理的任務隊列。實際上,在ThreadPoolExecutor中除此以外還存在一個正在處理的工做隊列workers:
keepAliveTime:超過核心線程數,又小於最大線程數目的線程在空閒的狀況下,多久回收。
threadFactory:線程工廠,實際上用的是默認的DefaultThreadFactory,經過代碼發現僅僅是針對Thread作了些設置(好比線程組/線程名稱/後臺/優先級等設置),將Runnable掛到Thread上而已。
handler:若是已經達到了最大線程數目,那麼對於任務只能開始拒絕了,這個就是拒絕處理的策略類。