jdk源碼之LinkedBlckingQueue源碼註釋

 今天咱們分析一下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

   搞定,手工!併發

相關文章
相關標籤/搜索