高併發程式設計-佇列-BlockingQueue-LinkedBlockingQueue
阿新 • • 發佈:2021-12-06
高併發程式設計-佇列-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); }