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也行呢?/<string>/<string>
我們測試下:
發現確實可以的。
我們來看看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
所以,從源碼中,我們可以得到如下總結:
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 的文章