一、簡介
LinkedBlockingQueue是BlockingQueue的一種使用Link List的實現,它對頭和尾(取和添加操作)採用兩把不同的鎖,相對於ArrayBlockingQueue提高了輸送量。它也是一種阻塞型的容器,適合於實現“消費者生產者”模式。
二、具體實現
LinkedBlockingQueue底層的定義如下:
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { static class Node<E> { /** The item, volatile to ensure barrier separating write and read */ volatile E item; Node<E> next; Node(E x) { item = x; } } // 支援原子操作 private final AtomicInteger count = new AtomicInteger(0); // 鏈表的頭和尾 private transient Node<E> head; private transient Node<E> last; // 針對取和添加操作的兩把鎖及其上的條件 private final ReentrantLock takeLock = new ReentrantLock(); private final Condition notEmpty = takeLock.newCondition(); private final ReentrantLock putLock = new ReentrantLock(); private final Condition notFull = putLock.newCondition(); ... }
LinkedBlockingQueue的添加操作:
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { private void insert(E x) { last = last.next = new Node<E>(x); } /** * signal方法在被調用時,當前線程必須擁有該condition相關的鎖! * Signal a waiting take. Called only from put/offer (which do not * otherwise ordinarily lock takeLock.) */ private void signalNotEmpty() { final ReentrantLock takeLock = this.takeLock; takeLock.lock(); try { notEmpty.signal(); } finally { takeLock.unlock(); } } public void put(E o) throws InterruptedException { if (o == null) throw new NullPointerException(); int c = -1; final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; // 使用putLock putLock.lockInterruptibly(); try { try { // 當容量已滿時,等待notFull條件 while (count.get() == capacity) notFull.await(); } catch (InterruptedException ie) { notFull.signal(); // propagate to a non-interrupted thread throw ie; } insert(o); // 取出當前值,並將原資料增加1 c = count.getAndIncrement(); // 容量不滿,再次啟用notFull上等待的put線程 if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock(); } // 必須先釋放putLock再在notEmpty上signal,否則會造成死結 if (c == 0) signalNotEmpty(); } ... }
LinkedBlockingQueue的取操作:
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable { private E extract() { Node<E> first = head.next; head = first; E x = first.item; first.item = null; return x; } private void signalNotFull() { final ReentrantLock putLock = this.putLock; putLock.lock(); try { notFull.signal(); } finally { putLock.unlock(); } } public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; // 使用takeLock takeLock.lockInterruptibly(); try { try { // 若容量為空白,等待notEmpty while (count.get() == 0) notEmpty.await(); } catch (InterruptedException ie) { notEmpty.signal(); // propagate to a non-interrupted thread throw ie; } x = extract(); c = count.getAndDecrement(); // 再次啟用notEmpty if (c > 1) notEmpty.signal(); } finally { takeLock.unlock(); } // take執行之前容量已滿,則啟用notFull if (c == capacity) signalNotFull(); return x; } ... }
ConcurrentLinkedQueue是一個無鎖的queue實現,它採用了一種無鎖演算法(在API中有說明),相比於傳統的同步的queue來說輸送量可以大大提高,同時它也不同於BlockingQueue,並不單單提供阻塞操作。它主要的目的是通過採用無鎖的演算法,使得read/write操作均不需要對容器加鎖,提高容器輸送量