Jdk-併發包-ArrayBlockingQueue

整體流程

在這裏插入圖片描述

組成元素

1)ReentrantLock:重入鎖,對操作加鎖,實現併發訪問控制,以及內存可見性
2)ReentrantLock.newCondition(notFull):非滿條件,數據出隊後,發送notFull信號(signal),通知因隊滿等待的線程,喚醒搶鎖。
3)ReentrantLock.newCondition(notEmpty):非空條件,數據入隊後,發送notEmpty信號,通知因隊空等待的線程,喚醒搶鎖。
4)items數組等基本隊列元素

流程描述

以插入爲例:

  1. 獲取鎖
  2. 循環判斷當前元素個數是否等於數組長度(有界隊列)
  3. 不等於,說明隊列未滿,直接退出循環,或者notFull.await(),釋放鎖,進入並掛起,代碼進入自旋狀態,等待notFull signal信號。否則進入5
  4. 等到notFull信號後,如果獲得鎖,則繼續4
  5. 等於則直接入隊,併發起notEmpty信號,喚醒等待此信號的線程。
  6. 釋放鎖
    public void put(E e) throws InterruptedException {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length)
                notFull.await();
            enqueue(e);
        } finally {
            lock.unlock();
        }
    }
    /**
     * Inserts element at current put position, advances, and signals.
     * Call only when holding lock.
     */
    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[putIndex] = x;
        if (++putIndex == items.length)
            putIndex = 0;
        count++;
        notEmpty.signal();
    }
    /**
     * Extracts element at current take position, advances, and signals.
     * Call only when holding lock.
     */
    private E dequeue() {
        // assert lock.getHoldCount() == 1;
        // assert items[takeIndex] != null;
        final Object[] items = this.items;
        @SuppressWarnings("unchecked")
        E x = (E) items[takeIndex];
        items[takeIndex] = null;
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal(); // 出隊後發送notFull信號
        return x;
    }

一些特殊點

1)構造函數加lock, 由於putIndex 、count等元素都爲使用volatile關鍵字修飾,所以如果不加lock,修改後的值不會立即同步到主存,所以需要lock獲得內存可見性,刷進主存:

    public ArrayBlockingQueue(int capacity, boolean fair,
                              Collection<? extends E> c) {
        this(capacity, fair);

        final ReentrantLock lock = this.lock;
        lock.lock(); // Lock only for visibility, not mutual exclusion
        try {
            int i = 0;
            try {
                for (E e : c) {
                    checkNotNull(e);
                    items[i++] = e;
                }
            } catch (ArrayIndexOutOfBoundsException ex) {
                throw new IllegalArgumentException();
            }
            count = i;
            putIndex = (i == capacity) ? 0 : i;
        } finally {
            lock.unlock();
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章