LinkedBlockingQueue中put源碼分析
阿新 • • 發佈:2018-04-29
資源 線程 ID 數量 integer cond 滿了 incr IT
查看源碼得知:
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(); } }
LinkedBlockingQueue中put源碼分析