Java中常用的七個阻塞佇列介紹第一篇
在上一篇我們對Java中的佇列分類做了簡單的介紹。本文我們們主要來聊聊阻塞佇列中的七個常用子類。這七個阻塞佇列的學習步驟:先看原始碼,分析完原始碼之後,我們再來對每個佇列進行總結。最後在來個大總結。文章可能有點長,但是,大家耐著性子看完,保證你對這七大阻塞佇列有深刻的理解。
本文主要內容:介紹前三個佇列及檢視原始碼總結每個佇列的特點
本文出自凱哥Java(kaigejava)的《凱哥Java併發系列》之《Java併發程式設計之佇列》系列的第二篇:《Java中常用的七個阻塞佇列介紹第一篇》
先來看看這七個子類的類圖:
都是BlockingQueue(阻塞佇列的父介面)的子類,而BlockingQueue最終又繼承於Collection介面。從而我們可以這麼說,阻塞佇列是Collection的子類的一個分支也沒問題。
阻塞佇列的七個子類:
ArrayBlockingQueue(下文簡稱:ABQueue)、LinkedBlockingQueue(下文簡稱:LBQueue)、PriorityBlockingQueue(下文簡稱:PBQueue)、DelayQueue(下文簡稱:DQueue)、SynchronouseQueue(下文簡稱:SyncQueue)、LinkedTrnsferQueue(下文簡稱:LTQueue)、LinkedBlockingDeque(下文簡稱:LBDeque)這個七個。我們來一個一個看。
ArrayBlockingQueue
在上面我們知道了阻塞佇列是集合的一個子類。我們也知道: Collection<String> c1 = new ArrayList<String>();這個是成立的。那麼是不是把ArrayList換成ArrayBlockingQueue也行呢?
我們測試下:
發現確實可以的。
我們來看看arrayBlockingQueue的構造器:
由三個構造器。程式碼如下:
我們看到,其實都呼叫的是:
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity];
lock = new ReentrantLock(fair);
notEmpty = lock.newCondition();
notFull = lock.newCondition();
}
從程式碼中我們可以看到:ABQueue底層是陣列結構。使用的是ReentrantLock鎖。再之前的文章中凱哥(凱哥Java:kaigejava)在講解ReentrantLock的時候,講過預設使用的是非公平的。
所以通過原始碼分析我們可以對ABQueue得到如下總結:
ABQueue結論:
ArrayBlockingQueue:是資料結構的有界的阻塞佇列。且預設使用非公平鎖,也就是不保證執行緒公平訪問佇列的。
為什麼說是有界的呢?因為我們知道陣列大小是有邊界的。無論你宣告的陣列多大,最後都一個極限的。存在大小限制,從原始碼中,來看看向佇列中新增資料的方法:
為什麼說預設不保證執行緒公平呢?因為RLock預設使用的就是非公平機制的。
如何保證公平呢?在宣告的時候,直接設定為true.
LinkedBlockingQueue
先來看看構造器:
和ABQueue類似都是由三個構造器。但是不同的是,LBQueue沒有強制輸入佇列大小的。預設使用的是Integer.MAX_VALUE.那麼這個數值是多大呢?2的31次方-1.大概是21億多。
從原始碼中,我們可以看出,last=head=new Node<E>()。從這行程式碼中,我們可以知道,LBQueue使用的是連結串列結構。也是使用的RLock鎖。
所以,從原始碼中,我們可以得到如下總結:
LBQueue結論:
LBQueue是使用連結串列結構的有界阻塞佇列。
為什麼說是有界的呢?我們來看看新增的元素的原始碼:
需要注意:千萬別用預設的。因為預設大小是Integer.MAX_VALUE。java int 類整數的最大值是 2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647。這個資料太大了。如果使用預設的話,也可以理解為無界的。
PriorityBlockingQueue
這個佇列名字拆開:
priority:中文的意思是優先的,優先通行權。這個佇列支援優先順序的。
來看看構造器:
如果不傳遞佇列數量。使用預設的。從原始碼中,我們可以看到預設建立初始的佇列大小是11.
我們來看看新增元素方法的原始碼:
從原始碼中,我們可以到,在新增的時候用了Comparator這個介面。而且在原始碼中,我們也沒看到對佇列的大小限制。
PBQueue總結:
PBQueue是一個支援優先順序的無界阻塞佇列。預設情況下元素採用自然順序升序排列。也可以自定義類來實現comparator介面的compare方法來實現自定義排序規則。或者是在初始化的時候呼叫public PriorityBlockingQueue(int initialCapacity,Comparator<? super E> comparator) {}這個構造器,支援在初始化的時候傳遞比較器。PBQueue佇列同樣使用了RLock,所以不能保證公平性。在新增的時候,不能新增null元素。否則會空指標異常。
為什麼說支援優先順序呢?新增元素的原始碼中使用了Comparator介面。而Comparator預設使用的是字典排序的。
程式碼演示
程式碼演示,PBQueue使用的預設排序順序是字典排序升序法。程式碼如下:
執行結果:
下面來演示自定義比較器。
先來看看自定義的倒序排序器
在來看看存放和獲取後:
ABQueue、LBQueue、PBQueue比較
名字 是否有界 資料結構 備註
ArrayBlockingQueue 有界的 陣列 "初始化的時候需要給定佇列大小;
預設非公平的。在初始化的時候可以給定是否使用公平鎖"
LinkedBlockingQueue 有界的 連結串列 "預設大小事Integer.Max_value.達到21億不建議使用預設的。"
PriorityBlockingQueue 無界的 連結串列 "支援優先順序的阻塞佇列。
預設適用自然排序升序規則
在初始化佇列的時候,可以給定比較器的"
《Java併發程式設計-JUC系列教程》: