1. 程式人生 > >多執行緒:執行緒池裡的佇列BlockingQueue

多執行緒:執行緒池裡的佇列BlockingQueue

runnableTaskQueue(任務佇列):用於儲存等待執行的任務的阻塞佇列。 可以選擇以下幾個阻塞佇列:

BlockingQueue的幾個注意點

【1】BlockingQueue 可以是限定容量的。它在任意給定時間都可以有一個remainingCapacity,超出此容量,便無法無阻塞地put 附加元素。沒有任何內部容量約束的BlockingQueue 總是報告Integer.MAX_VALUE 的剩餘容量。

【2】BlockingQueue 實現主要用於生產者-使用者佇列,但它另外還支援Collection 介面。

【3】BlockingQueue 實現是執行緒安全的。

【4】BlockingQueue 實質上不支援使用任何一種“close”或“shutdown”操作來指示不再新增任何項。


1)ArrayBlockingQueue:規定大小的BlockingQueue,其建構函式必須帶一個int引數來指明其大小.其所含的物件是以FIFO(先入先出)順序排序的.

1:它是有界阻塞佇列。它是陣列實現的,是一個典型的“有界快取區”。陣列大小在建構函式指定,而且從此以後不可改變。

2:是它執行緒安全的,是阻塞的,具體參考BlockingQueue的“注意4”。

3:不接受 null 元素

4:公平性 (fairness)可以在建構函式中指定。如果為true,則按照FIFO 順序訪問插入或移除時受阻塞執行緒的佇列;如果為 false,則訪問順序是不確定的。

5:它實現了BlockingQueue介面。關於BlockingQueue,請參照《BlockingQueue》

6:此類及其迭代器實現了 Collection 和 Iterator 介面的所有可選 方法。

7:其容量在建構函式中指定。容量不可以自動擴充套件,也沒提供手動擴充套件的介面。

8:在JDK5/6中,LinkedBlockingQueue和ArrayBlocingQueue等物件的poll(long timeout, TimeUnit unit)存在記憶體洩露Leak的物件是AbstractQueuedSynchronizer.Node,

2)LinkedBlockingQueue:大小不定的BlockingQueue,若其建構函式帶一個規定大小的引數,生成的BlockingQueue有大小限制,若不帶大小引數,所生成的BlockingQueue的大小由Integer.MAX_VALUE來決定.其所含的物件是以FIFO(先入先出)順序排序的併發庫中的BlockingQueue是一個比較好玩的類,顧名思義,就是阻塞佇列。該類主要提供了兩個方法put()和take(),前者將一個物件放到佇列中,如果佇列已經滿了,就等待直到有空閒節點;後者從head取一個物件,如果沒有物件,就等待直到有可取的物件。

3)PriorityBlockingQueue:類似於LinkedBlockQueue,但其所含物件的排序不是FIFO,而是依據物件的自然排序順序或者是建構函式的Comparator決定的順序.

1:它是無界阻塞佇列,容量是無限的,它使用與類PriorityQueue相同的順序規則。

2:它是執行緒安全的,是阻塞的

3:不允許使用 null 元素。

4:對於put(E o)和offer(E o, long timeout, TimeUnit unit),由於該佇列是無界的,所以此方法永遠不會阻塞。因此引數timeout和unit沒意義,會被忽略掉。

5:iterator() 方法中所提供的迭代器並不保證以特定的順序遍歷 PriorityBlockingQueue 的元素。

如果需要有序地遍歷,則應考慮使用 Arrays.sort(pq.toArray())。

6.至於使用和別的BlockingQueue(ArrayBlockingQueue,LinkedBlockingQueue)相似,可以參照它們。7:此類及其迭代器實現了 Collection 和 Iterator 介面的所有可選 方法。

4)SynchronousQueue:特殊的BlockingQueue,對其的操作必須是放和取交替完成的.(每個插入操作必須等到另一個執行緒呼叫移除操作,否則插入操作一直處於阻塞狀態,)此佇列不允許 null 元素。

SynchronousQueue的定義如下

public classSynchronousQueueextendsAbstractQueueimplementsBlockingQueue,Serializable

從上面可以看出,它實現BlockingQueue,所以是阻塞佇列,從名字看,它又是同步的。

它模擬的功能類似於生活中一手交錢一手交貨這種情形,像那種貨到付款或者先付款後發貨模型不適合使用SynchronousQueue。

首先要知道SynchronousQueue沒有容納元素的能力,即它的isEmpty()方法總是返回true

另外在建立SynchronousQueue時可以傳遞一個boolean引數來指定它是否是訪問它的執行緒按遵守FIFO順序處理,true表示遵守FIFO。

5)DelayQueue

是一個無界的BlockingQueue,用於放置實現了Delayed介面的物件,其中的物件只能在其到期時才能從佇列中取走。這種佇列是有序的,即隊頭物件的延遲到期時間最長。注意:不能將null元素放置到這種佇列中。


四種執行緒池各自的特點及所用到的佇列

newCachedThreadPool()快取型池子,先檢視池中有沒有以前建立的執行緒,如果有,就reuse.如果沒有,就建一個新的執行緒加入池中。能reuse的執行緒,必須是timeout IDLE內的池中執行緒,預設timeout是60s,超過這個IDLE時長,執行緒例項將被終止及移出池。快取型池子通常用於執行一些生存期很短的非同步型任務。所用佇列為SynchronousQueue()

newFixedThreadPool()fixedThreadPool與cacheThreadPool差不多,也是能reuse就用,但不能隨時建新的執行緒其獨特之處:任意時間點,最多隻能有固定數目的活動執行緒存在,此時如果有新的執行緒要建立,只能放在另外的佇列中等待,直到當前的執行緒中某個執行緒終止直接被移出池子。和cacheThreadPool不同:fixedThreadPool池執行緒數固定,但是0秒IDLE(無IDLE)。這也就意味著建立的執行緒會一直存在。所以fixedThreadPool多數針對一些很穩定很固定的正規併發執行緒,多用於伺服器。所用佇列為LinkedBlockingQueue()

newScheduledThreadPool()排程型執行緒池。這個池子裡的執行緒可以按schedule依次delay執行,或週期執行 。0秒IDLE(無IDLE)。所用佇列為DelayedWorkQueue()

newSingleThreadExecutor()單例執行緒,任意時間池中只能有一個執行緒。用的是和cache池和fixed池相同的底層池,但執行緒數目是1-1,0秒IDLE(無IDLE)。所用佇列為LinkedBlockingQueue()