Java中常用的七個阻塞隊列介紹第一篇

Java中常用的七個阻塞隊列介紹第一篇

在上一篇我們對Java中的隊列分類做了簡單的介紹。本文咱們主要來聊聊阻塞隊列中的七個常用子類。這七個阻塞隊列的學習步驟:先看源碼,分析完源碼之後,我們再來對每個隊列進行總結。最後在來個大總結。文章可能有點長,但是,大家耐著性子看完,保證你對這七大阻塞隊列有深刻的理解。

本文主要內容:介紹前三個隊列及查看源碼總結每個隊列的特點

本文出自凱哥Java(kaigejava)的《凱哥Java併發系列》之《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>

我們測試下:

Java中常用的七個阻塞隊列介紹第一篇

發現確實可以的。

我們來看看arrayBlockingQueue的構造器:

Java中常用的七個阻塞隊列介紹第一篇

由三個構造器。代碼如下:

Java中常用的七個阻塞隊列介紹第一篇

我們看到,其實都調用的是:

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:是數據結構的有界的阻塞隊列。且默認使用非公平鎖,也就是不保證線程公平訪問隊列的。

為什麼說是有界的呢?因為我們知道數組大小是有邊界的。無論你聲明的數組多大,最後都一個極限的。存在大小限制,從源碼中,來看看向隊列中添加數據的方法:

Java中常用的七個阻塞隊列介紹第一篇

為什麼說默認不保證線程公平呢?因為RLock默認使用的就是非公平機制的。

如何保證公平呢?在聲明的時候,直接設置為true.

Java中常用的七個阻塞隊列介紹第一篇

LinkedBlockingQueue

先來看看構造器:

Java中常用的七個阻塞隊列介紹第一篇

Java中常用的七個阻塞隊列介紹第一篇

和ABQueue類似都是由三個構造器。但是不同的是,LBQueue沒有強制輸入隊列大小的。默認使用的是Integer.MAX_VALUE.那麼這個數值是多大呢?2的31次方-1.大概是21億多。

從源碼中,我們可以看出,last=head=new Node()。從這行代碼中,我們可以知道,LBQueue使用的是鏈表結構。也是使用的RLock鎖。

所以,從源碼中,我們可以得到如下總結:

LBQueue結論:

LBQueue是使用鏈表結構的有界阻塞隊列。

為什麼說是有界的呢?我們來看看添加的元素的源碼:

Java中常用的七個阻塞隊列介紹第一篇

需要注意:千萬別用默認的。因為默認大小是Integer.MAX_VALUE。java int 類整數的最大值是 2 的 31 次方 - 1 = 2147483648 - 1 = 2147483647。這個數據太大了。如果使用默認的話,也可以理解為無界的。

PriorityBlockingQueue

這個隊列名字拆開:

priority:中文的意思是優先的,優先通行權。這個隊列支持優先級的。

來看看構造器:

Java中常用的七個阻塞隊列介紹第一篇

如果不傳遞隊列數量。使用默認的。從源碼中,我們可以看到默認創建初始的隊列大小是11.

Java中常用的七個阻塞隊列介紹第一篇

我們來看看添加元素方法的源碼:

Java中常用的七個阻塞隊列介紹第一篇

從源碼中,我們可以到,在添加的時候用了Comparator這個接口。而且在源碼中,我們也沒看到對隊列的大小限制。

PBQueue總結:

PBQueue是一個支持優先級的無界阻塞隊列。默認情況下元素採用自然順序升序排列。也可以自定義類來實現comparator接口的compare方法來實現自定義排序規則。或者是在初始化的時候調用public PriorityBlockingQueue(int initialCapacity,Comparator super E> comparator) {}這個構造器,支持在初始化的時候傳遞比較器。PBQueue隊列同樣使用了RLock,所以不能保證公平性。在添加的時候,不能添加null元素。否則會空指針異常。

為什麼說支持優先級呢?添加元素的源碼中使用了Comparator接口。而Comparator默認使用的是字典排序的。

代碼演示

代碼演示,PBQueue使用的默認排序順序是字典排序升序法。代碼如下:

Java中常用的七個阻塞隊列介紹第一篇

運行結果:

Java中常用的七個阻塞隊列介紹第一篇

下面來演示自定義比較器。

先來看看自定義的倒序排序器

Java中常用的七個阻塞隊列介紹第一篇

在來看看存放和獲取後:

Java中常用的七個阻塞隊列介紹第一篇

ABQueue、LBQueue、PBQueue比較

名字 是否有界 數據結構 備註

ArrayBlockingQueue 有界的 數組 "初始化的時候需要給定隊列大小;

默認非公平的。在初始化的時候可以給定是否使用公平鎖"

LinkedBlockingQueue 有界的 鏈表 "默認大小事Integer.Max_value.達到21億不建議使用默認的。"

PriorityBlockingQueue 無界的 鏈表 "支持優先級的阻塞隊列。

默認適用自然排序升序規則

在初始化隊列的時候,可以給定比較器的"

Java中常用的七個阻塞隊列介紹第一篇


分享到:


相關文章: