檢視原始碼得知:
LinkedBlockingQueue採用是鎖分離的技術
//取出鎖 private final ReentrantLock takeLock = new ReentrantLock(); //取出鎖條件 private final Condition notEmpty = takeLock.newCondition(); //插入鎖 private final ReentrantLock putLock = new ReentrantLock(); //插入鎖條件 private final Condition notFull = putLock.newCondition();
檢視put方法原始碼
public void put(E e) throws InterruptedException { //判斷元素為空 if (e == null) throw new NullPointerException(); //設定元素值 int c = -1; //建立節點 Node<E> node = new Node<E>(e); //獲取插入鎖 final ReentrantLock putLock = this.putLock; //設定數量 final AtomicInteger count = this.count; //嘗試加鎖 putLock.lockInterruptibly(); try { //判斷如果這個數量等於容器數量說明容器滿了 while (count.get() == capacity) { //等待 notFull.await(); } //插入 enqueue(node); //長度+1 //這裡獲取的c應該是原本的資料,getAndIncrement相當於i++ c = count.getAndIncrement(); //判斷其+1後是否小於容器體積 if (c + 1 < capacity) //小於則通知其他插入執行緒進行插入 notFull.signal(); } finally { //解鎖 putLock.unlock(); } //如果c==0表示本來沒有元素,現在已經有元素了 //所以必須將其queue中的等待釋放 if (c == 0) signalNotEmpty(); }
其中這句原始碼理解挺久的:為何要加入這句話呢?
if (c == 0) signalNotEmpty();
由於c為獲取的是新增元素前的資料,判斷為0說明之前該佇列為空,導致take方法中的執行緒處於等待的狀態,通過該方法可以使得其take方法中的等待執行緒釋放,讓其可以獲取資源,如下c為獲取的為原本queue長度
//這裡獲取的c應該是原本的資料,getAndIncrement相當於i++ c = count.getAndIncrement();
signalNotEmpty方法
private void signalNotEmpty() { //獲取取出鎖 final ReentrantLock takeLock = this.takeLock; //由於後面需要進行通知操作,所以得先獲取鎖 takeLock.lock(); try { //通知現在queue裡面有元素了,大家可以來獲取元素了 notEmpty.signal(); } finally { //解鎖 takeLock.unlock(); } }