1. 程式人生 > 其它 >高併發程式設計-佇列-BlockingQueue-LinkedBlockingQueue

高併發程式設計-佇列-BlockingQueue-LinkedBlockingQueue

高併發程式設計-佇列-BlockingQueue-LinkedBlockingQueue

一、LinkedBlockingQueue簡介

  LinkedBlockingQueue是一個基於連結串列的阻塞佇列,該佇列在建立時候,預設大小為Integer.MAX_VALUE,這個數值很大的,所以可以說LinkedBlockingQueue的大小沒有限制的,業界有個比較專業的詞彙,把它叫做無界佇列。但是這也帶來了一些問題,比如當JVM記憶體比較小的時候,可能就會出現OOM的情況。所以建議大家在使用的時候根據實際情況設定一個大小。

  LinkedBlockingQueue的內部是單向連結串列,在連結串列的內部只能next,也就是說查詢元素只能從head查起,從tail插入。

  LinkedBlockingQueue的採用兩把鎖的分離技術,實現了出隊和入隊的鎖分離,也就是說LinkedBlockingQueue的讀寫是分離的,提高了它得併發處理能力

二、LinkedBlockingQueue的特點

佇列特點:無界阻塞佇列,可以指定容量,預設為Integer.MAX_VALUE,先進先出
資料結構: 連結串列結構
鎖特點:讀寫鎖分離,操作各自的node物件。takeLock 取node節點保證了順序不會亂,putlock存資料時保證了有序
條件阻塞:出隊時候,如果佇列的count=0,證明佇列裡面沒有元素的,notEmpty條件佇列會被阻塞。入隊時候,如果佇列的count=capacity,證明佇列已滿,這個時候入隊執行緒需要阻塞,notFull需要阻塞。
入隊:從tail入隊。出隊:從head出隊

三、LinkedBlockingQueue的簡單實用

//建立一個有界佇列,這個需要指定大寫
BlockingQueue<Integer> linkedBlockingQueue = new LinkedBlockingQueue<>(100)
//預設指定的Queue為無界佇列
BlockingQueue<Integer> linkedBlockingQueue = new LinkedBlockingQueue<>();

//建議大家在使用的時候指定佇列大小,防止出現OOM

四、LinkedBlockingQueue的原始碼

資料引數

//指定佇列容量大小,不指定預設 Integer.MAX_VALUE
private final int capacity;
//統計內部元素數量,這裡使用了CAS的原子性操作
private final AtomicInteger count = new AtomicInteger();
//定義連結串列的頭部,初始化時 head=null
transient Node<E> head;
//定義連結串列的尾部
private transient Node<E> last;
//定義take poll使用的鎖,也就是消費者使用的鎖
private final ReentrantLock takeLock = new ReentrantLock();
//等待佇列的條件佇列,當佇列無元素時,take鎖會阻塞在notEmpty條件上,等待其它執行緒喚醒
private final Condition notEmpty = takeLock.newCondition();
//定義 put, offer,使用的鎖,也就是生產者使用的鎖
private final ReentrantLock putLock = new ReentrantLock();
//等待入隊的條件佇列,當佇列滿了時,put鎖會會阻塞在notFull上,等待其它執行緒喚醒
private final Condition notFull = putLock.newCondition();


//單鏈表結構
 static class Node<E> {
        E item;//儲存元素

        Node<E> next;//後續節點,單鏈表結構

        Node(E x) { item = x; }
    }

構造器

//預設的構造器 
public LinkedBlockingQueue() {
// 如果沒傳容量,就使用最大int值初始化其容量
        this(Integer.MAX_VALUE);
    }

//指定容量大小的構造器
 public LinkedBlockingQueue(int capacity) {
    //如果指定容量大小小於等於0丟擲異常
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
//定義初始的head和last節點,初始為空節點
        last = head = new Node<E>(null);
    }