Java中常用的七個阻塞隊列介紹第一篇
- 2020 年 4 月 20 日
- 筆記
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系列教程》: