JDK 線程安全集合源碼筆記

阻塞隊列

LinkedBlockingQueue

當隊列爲空,消費者線程被阻塞;當隊列裝滿,生產者線程被阻塞。這是阻塞隊列的基本特點。LinkedBlockingQueue對鎖進行了優化,就是put鎖和take鎖分離。

另外,線程協作通知方式,不都是生產者直接喚醒全部消費者,而是生產者通知一個消費者線程,消費者線程發現還有可取的元素,會通知其他消費者線程。稱爲Cascading notification。

下面對源碼進行簡要分析:

	// 鏈表節點數,這裏final代表的是引用不可變,而不是值不可變
    /** Current number of elements */
    private final AtomicInteger count = new AtomicInteger();

    /**
     * Head of linked list.
     * Invariant: head.item == null
     */
    transient Node<E> head;

    /**
     * Tail of linked list.
     * Invariant: last.next == null
     */
    private transient Node<E> last;
	
	// take鎖,消費者線程需要的鎖
    /** Lock held by take, poll, etc */
    private final ReentrantLock takeLock = new ReentrantLock();
	
    /** Wait queue for waiting takes */
    private final Condition notEmpty = takeLock.newCondition();
	// put鎖,生產者需要的鎖
    /** Lock held by put, offer, etc */
    private final ReentrantLock putLock = new ReentrantLock();
    /** Wait queue for waiting puts */
    private final Condition notFull = putLock.newCondition();

到這裏位置,阻塞隊列的狀態基本定義完了,下面看簡單的生產者線程的put。

  */
    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);
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger count = this.count;
        putLock.lockInterruptibly();
        try {
            /*
             * Note that count is used in wait guard even though it is
             * not protected by lock. This works because count can
             * only decrease at this point (all other puts are shut
             * out by lock), and we (or some other waiting put) are
             * signalled if it ever changes from capacity. Similarly
             * for all other uses of count in other wait guards.
             */
            while (count.get() == capacity) {
                notFull.await();
            }
            enqueue(node);
            c = count.getAndIncrement();
            if (c + 1 < capacity)
            	//這裏就是生產者線程通知其他生產者線程,隊列沒滿
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0)
        	// 這裏是通知消費者線程
            signalNotEmpty();
    }

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章