1. 程式人生 > >Java中常用的七個阻塞佇列介紹第一篇

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

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系列教程》:

&n