今天咱們分析一下LinkedBlockingQueue,這是一個咱們使用頻率比較高的類。java
public static void main(String[] args) throws Exception { //咱們這個LinkedBlockingQueue源碼分三個關鍵步驟 //步驟一:先看一個其構造函數,以及核心的屬性 LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>(); //步驟二:看一下其關鍵步驟,插入數據的步驟 queue.put("張三"); //步驟三:看一下其關鍵步驟,獲取數據的步驟 queue.take(); } 步驟一: public LinkedBlockingQueue() { //設置隊列的大小 //其實可見,默認狀況下是一個無界隊列(相似於無界) this(Integer.MAX_VALUE); } public LinkedBlockingQueue(int capacity) { if (capacity <= 0) throw new IllegalArgumentException(); //設置隊列大小 this.capacity = capacity; //初始化一個空節點 last = head = new Node<E>(null); } //獲取數據的時候的一把鎖 //由於是隊列,這把鎖在隊尾 private final ReentrantLock takeLock = new ReentrantLock(); //關於takeLock的對象 private final Condition notEmpty = takeLock.newCondition(); //put數據的時候的一把鎖 //由於是隊列,因此這把鎖在隊頭 private final ReentrantLock putLock = new ReentrantLock(); //關於putLock的對象 private final Condition notFull = putLock.newCondition(); 其實LinkedBlockingQueue的設計也是很巧妙的,使用了兩把鎖去控制。兩把鎖之間互相不影響。大幅提高了併發的性能。 接下來自咱們分析一下步驟二: public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; //根據當前傳入的元素封裝節點 Node<E> node = new Node<E>(e); //獲取putLocak鎖 final ReentrantLock putLock = this.putLock; //統計當前元數據個數 final AtomicInteger count = this.count; //加鎖 putLock.lockInterruptibly(); try { //若是隊列存滿了,那就等待 while (count.get() == capacity) { notFull.await(); } //入隊,這個操做其實也很簡單 // last = last.next = node; enqueue(node); //入隊完了之後遞增當前 元素個數 //不過咱們須要知道的是,好比當前的元素個數 //已是9遞增到10了。 //這個時候count=10 c=9 c = count.getAndIncrement(); //若是c+1小於總的容量,說明隊列至少有一個空間是能夠存數據的。 if (c + 1 < capacity) //喚醒以前由於隊列滿了而處於等待的鎖。 notFull.signal(); } finally { //釋放鎖 putLock.unlock(); } //若是c==0,說明當前的隊列裏面確定還有元素,能夠獲取 if (c == 0) //喚醒以前由於隊列爲空而處於等待的鎖 signalNotEmpty(); } 咱們發現其實LinkedBlockingQueue的源碼閱讀下來難度不大。 public E take() throws InterruptedException { E x; int c = -1; //獲取當前元素個數 final AtomicInteger count = this.count; //獲取takeLock鎖 final ReentrantLock takeLock = this.takeLock; //獲取元素的時候加鎖 takeLock.lockInterruptibly(); try { //若是當前元素等於0,說明沒有元素了 while (count.get() == 0) { //若是隊列爲空,那麼就等待 notEmpty.await(); } //出隊,獲取元素 //出隊的代碼也是極其簡單就是變化一下指針就能夠。 x = dequeue(); //遞減元素 //加入當前count 由10 變成了9 //count =10 count=9 c = count.getAndDecrement(); //說明隊列不爲空 if (c > 1) //不爲空,那麼就喚醒 可能由於隊列爲空而處於等待的鎖 notEmpty.signal(); } finally { //釋放鎖 takeLock.unlock(); } //若是c==capacity說明隊列裏面確定會有不滿的元素 if (c == capacity) //喚醒,由於隊列滿了而處於等待的鎖。 signalNotFull(); //返回當前元素 return x; }
若是有了以前的基礎,閱讀這段代碼應該是比較簡單的。node
搞定,手工!併發