ArrayBlockingQueue源码解读

ArrayBlockingQueue是一个基于数组实现的有界的阻塞队列。

属性

    //底层存储元素的数组。为final说明一旦初始化,容量不可变,所以是有界的。
    final Object[] items;

    //下一个take, poll, peek or remove操作的index位置
    int takeIndex;
    
    //下一个put, offer, or add操作的index位置
    int putIndex;

    // 元素数量
    int count;

    /**
     * 用于并发控制:使用经典的双Condition算法
     */
    final ReentrantLock lock;
    /** 获取操作等待条件 */
    private final Condition notEmpty;
    /** 插入操作等待条件 */
    private final Condition notFull;

添加操作

1.add操作(不常用)

add()是最原始的方法。当队列满时,会抛出IllegalStateException。

    public boolean add(E e) {
        return super.add(e);
    }
    
    // 父类AbstractQueue中的add()
    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

2.offer操作

offer有两个版本。
不带超时版本:队列满时,直接返回false。
带超时版本:队列满时,阻塞直到队列可用。

    public boolean offer(E e) {
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //队列已满,直接返回false
            if (count == items.length)
                return false;
            else {//未满,则插入元素
                insert(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }
    
    /**offer,带超时版本**/
    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) {
                //超时,则直接返回false
                if (nanos <= 0)
                    return false;
                //队列已满,则等待
                nanos = notFull.awaitNanos(nanos);
            }
            //阻塞直到队列可用,则插入元素
            insert(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

3.put操作

    public void put(E e) throws InterruptedException {
        //检查参数是否为null。为null则抛异常
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        //加锁。可中断
        lock.lockInterruptibly();
        try {
            //队列已满则一直等待,直到队列有可用空间
            while (count == items.length)
                notFull.await();//等待
            //队列空闲时,插入元素
            insert(e);
        } finally {
            //释放锁
            lock.unlock();
        }
    }

删除操作

1.poll操作

    public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0) ? null : extract();
        } finally {
            lock.unlock();
        }
    }
    
    private E extract() {
        final Object[] items = this.items;
        E x = this.<E>cast(items[takeIndex]);//强转
        //删除
        items[takeIndex] = null;
        takeIndex = inc(takeIndex);
        --count;
        //通知
        notFull.signal();
        return x;
    }
    
    /**poll,带超时版本**/
    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 extract();
        } finally {
            lock.unlock();
        }
    }

2.take操作

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == 0)
                notEmpty.await();
            return extract();
        } finally {
            lock.unlock();
        }
    }

3.peek操作

    public E peek() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return (count == 0) ? null : itemAt(takeIndex);
        } finally {
            lock.unlock();
        }
    }

清空操作

    public void clear() {
        final Object[] items = this.items;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //依次将所有元素设为null
            for (int i = takeIndex, k = count; k > 0; i = inc(i), k--)
                items[i] = null;
            //count,putIndex,takeIndex都为0
            count = 0;
            putIndex = 0;
            takeIndex = 0;

            notFull.signalAll();
        } finally {
            lock.unlock();
        }
    }

 

 

总结

BlockingQueue接口提供了3个添加元素方法。

  • add:添加元素到队列里,添加成功返回true,如果队列已满则抛出IllegalStateException异常。不常用。
  • offer:添加元素到队列里,添加成功返回true,如果队列已满添加失败,返回false
  • put:添加元素到队列里,添加成功返回true,如果队列已满则阻塞直到队列可用

同时,BlockingQueue接口提供了3个获取(并删除)元素的方法。

  • remove:
  • poll:返回队列头部元素。队列为空时,返回null
  • take:队列为空时,会阻塞直到有数据加入到队列中
posted @ 2019-01-19 15:38  静水楼台/Java部落阁  阅读(447)  评论(0编辑  收藏  举报