ArrayBlockingQueue類源碼分析

本節學習ArrayBlockingQueue的源碼:

1.首先看類的定義

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable

可以看到類繼承了AbstractQueue且實現了接口BlockingQueue

public abstract class AbstractQueue<E>
    extends AbstractCollection<E>
    implements Queue<E> {

    /**
     * 構造方法
     */
    protected AbstractQueue() {
    }

    /**
     * 添加元素,如果添加成功,則返回true,否則異常
     */
    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

    /**
     * 移除元素,如果移除成功,返回被移除的元素,否則異常
     */
    public E remove() {
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

    /**
     * 獲取元素,如果獲取到元素,則返回,否則異常
     */
    public E element() {
        E x = peek();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

    /**
     * 清空隊列
     */
    public void clear() {
        while (poll() != null)
            ;
    }

    /**
     * 添加元素,如果添加成功,則返回true,否則返回false,或者異常
     */
    public boolean addAll(Collection<? extends E> c) {
        if (c == null)
            throw new NullPointerException();
        if (c == this)
            throw new IllegalArgumentException();
        boolean modified = false;
        for (E e : c)
            if (add(e))
                modified = true;
        return modified;
    }

}

2.類的變量信息

   /** 使用數組保存隊列元素 */
    final Object[] items;

    /** 下一個去除或者移除的元素的下標位置 */
    int takeIndex;

    /** 下一個添加的元素的下標位置 */
    int putIndex;

    /** 隊列中元素的個數 */
    int count;

    /** 控制所有訪問的重入鎖 */
    final ReentrantLock lock;

    /** 取出元素的條件 */
    private final Condition notEmpty;

    /** 添加元素的條件 */
    private final Condition notFull;

    /**
     * Shared state for currently active iterators, or null if there
     * are known not to be any.  Allows queue operations to update
     * iterator state.
     */
    transient Itrs itrs = null;

3.添加元素的四個方法

3.1 add 調用的抽象隊列中的添加方法,會拋異常

    public boolean add(E e) {
        return super.add(e);
    }

3.2 offer如果隊列滿了,則直接返回false。

    public boolean offer(E e) {
        checkNotNull(e);//元素判空,如果爲空,則拋空指針異常
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count == items.length)//如果隊列元素滿了,則返回false
                return false;
            else {
                enqueue(e);//否則
                return true;
            }
        } finally {
            lock.unlock();
        }
    }
    private void enqueue(E x) {
        // assert lock.getHoldCount() == 1;
        // assert items[putIndex] == null;
        final Object[] items = this.items;
        items[putIndex] = x;//設置putIndex下標元素爲x
        if (++putIndex == items.length)//如果putIndex加1後的長度等於數組長度,則設置putIndex爲0
            putIndex = 0;
        count++;//數組元素個數+1
        notEmpty.signal();//喚醒取元素條件
    }

3.3 put 可以中斷且如果隊列元素滿了,要進入等待狀態。

    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();
        }
    }

3.4 offer可終端,超時時間內可以阻塞等待,超時後如果隊列還是滿的,則返回false。

    public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {

        checkNotNull(e);//非空校驗
        long nanos = unit.toNanos(timeout);//超時時間
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length) {
                if (nanos <= 0)//如果隊列滿了且超過等待時間,則返回false
                    return false;
                nanos = notFull.awaitNanos(nanos);//否則添加元素的條件等待nanos時間
            }
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

4.取元素的幾個方法

4.1 poll 如果隊列中沒有元素,則返回null

    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0) ? null : dequeue();
        } finally {
            lock.unlock();
        }
    }
    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;//設置元素爲null
        if (++takeIndex == items.length)
            takeIndex = 0;
        count--;
        if (itrs != null)
            itrs.elementDequeued();
        notFull.signal();//添加元素的條件喚醒
        return x;
    }
4.2 take 可中斷,如果隊列爲空,則進入等待。
    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)//如果沒有可移除的元素,則移除元素的條件等待
                notEmpty.await();
            return dequeue();//移除元素
        } finally {
            lock.unlock();
        }
    }

4.3 poll 可中斷,如果隊列爲空,在等待時間內會進入等待狀態,過了等待時間返回null。

    public E poll(long timeout, TimeUnit unit) throws InterruptedException {
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0) {
                if (nanos <= 0)
                    return null;
                nanos = notEmpty.awaitNanos(nanos);
            }
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

4.4 remove

    public boolean remove(Object o) {
        if (o == null) return false;
        final Object[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count > 0) {//如果隊列不爲空
                final int putIndex = this.putIndex;
                int i = takeIndex;
                do {
                    if (o.equals(items[i])) {
                        removeAt(i); 移除元素
                        return true;
                    }
                    if (++i == items.length)
                        i = 0;
                } while (i != putIndex);
            }
            return false;
        } finally {
            lock.unlock();
        }
    }
    void removeAt(final int removeIndex) {
        // assert lock.getHoldCount() == 1;
        // assert items[removeIndex] != null;
        // assert removeIndex >= 0 && removeIndex < items.length;
        final Object[] items = this.items;
        if (removeIndex == takeIndex) {
            // removing front item; just advance
            items[takeIndex] = null;
            if (++takeIndex == items.length)
                takeIndex = 0;
            count--;
            if (itrs != null)
                itrs.elementDequeued();
        } else {
            // an "interior" remove

            // slide over all others up through putIndex.
            final int putIndex = this.putIndex;
            for (int i = removeIndex;;) {
                int next = i + 1;
                if (next == items.length)
                    next = 0;
                if (next != putIndex) {
                    items[i] = items[next];
                    i = next;
                } else {
                    items[i] = null;
                    this.putIndex = i;
                    break;
                }
            }
            count--;
            if (itrs != null)
                itrs.removedAt(removeIndex);
        }
        notFull.signal();
    }

5 其他方法

5.1 peek 返回下個要移除的元素值。

    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return itemAt(takeIndex); // null when queue is empty
        } finally {
            lock.unlock();
        }
    }

5.2 size 返回隊列元素的個數

    public int size() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return count;
        } finally {
            lock.unlock();
        }
    }

5.3 remainingCapacity 返回隊列剩餘的空間

    public int remainingCapacity() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return items.length - count;
        } finally {
            lock.unlock();
        }
    }

5.4 contains判斷隊列中是否包含元素o

    public boolean contains(Object o) {
        if (o == null) return false;
        final Object[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            if (count > 0) {
                final int putIndex = this.putIndex;
                int i = takeIndex;
                do {
                    if (o.equals(items[i]))
                        return true;
                    if (++i == items.length)
                        i = 0;
                } while (i != putIndex);
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

5.5 clear 清空隊列,且喚醒所有添加數據的條件

    public void clear() {
        final Object[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int k = count;
            if (k > 0) {
                final int putIndex = this.putIndex;
                int i = takeIndex;
                do {
                    items[i] = null;
                    if (++i == items.length)
                        i = 0;
                } while (i != putIndex);
                takeIndex = putIndex;
                count = 0;
                if (itrs != null)
                    itrs.queueIsEmpty();
                for (; k > 0 && lock.hasWaiters(notFull); k--)
                    notFull.signal();
            }
        } finally {
            lock.unlock();
        }
    }

總結:

有界阻塞隊列,底層數據結構是數組。

同步控制使用的重入鎖和condition。

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