Java8 ArrayBlockingQueue 源码解析

    目录

1、定义

2、构造方法

3、add / offer / put 

4、poll / take / peek

5、remove / clear /drainTo

6、iterator / Itr / Itrs 

7、doSomeSweeping  /  register

8、queueIsEmpty / elementDequeued / takeIndexWrapped / removedAt

9、next / hasNext / remove


      ArrayBlockingQueue表示一个基于数组实现的固定容量的,先进先出的,线程安全的队列(栈),本篇博客就详细讲解该类的实现细节。

1、定义

    ArrayBlockingQueue的类继承关系如下:

其核心接口BlockingQueue包含的方法定义如下:

上图中的Queue和Collection下面都有两个接口,这两个接口是BlockingQueue覆写的,并不是说这两类只有这两接口,Collection和Queue的主要接口实现都由AbstractQueue实现了,我们重点关注上图中列出来的这些接口的实现。

ArrayBlockingQueue包含的属性如下:

     /**保存队列元素的数组 */
    final Object[] items;

    /** items index for next take, poll, peek or remove */
    int takeIndex;

    /** offer,add,put等方法将元素保存到该索引处 */
    int putIndex;

    /** 队列中元素的个数 */
    int count;

    /** 互斥锁*/
    final ReentrantLock lock;

    /** 如果数组是空的,在该Condition上等待 */
    private final Condition notEmpty;

    /** 如果数组是满的,在该Condition上等待 */
    private final Condition notFull;

    /** 遍历器实现 */
    transient Itrs itrs = null;

 重点关注以下方法的实现。

2、构造方法

public ArrayBlockingQueue(int capacity) {
        this(capacity, false);
    }

//capacity表示队列的容量,fair表示是否使用公平锁
public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }

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

        final ReentrantLock lock = this.lock;
        //加锁的目的是为了其他CPU能够立即看到修改
        //加锁和解锁底层都是CAS,会强制修改写回主存,对其他CPU可见
        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();
        }
    }

3、add / offer / put 

     这三个方法都是往队列中添加元素,说明如下:

  • add方法依赖于offer方法,如果队列满了则抛出异常,否则添加成功返回true;
  • offer方法有两个重载版本,只有一个参数的版本,如果队列满了就返回false,否则加入到队列中,返回true,add方法就是调用此版本的offer方法;另一个带时间参数的版本,如果队列满了则等待,可指定等待的时间,如果这期间中断了则抛出异常,如果等待超时了则返回false,否则加入到队列中返回true;
  • put方法跟带时间参数的offer方法逻辑一样,不过没有等待的时间限制,会一直等待直到队列有空余位置了,再插入到队列中,返回true
public boolean add(E e) {
        //调用子类offer方法实现,如果队列满了则抛出异常
        return super.add(e);
    }

public boolean offer(E e) {
        //非空检测
        checkNotNull(e);
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //数组满了
            if (count == items.length)
                return false;
            else {
                enqueue(e);
                return true;
            }
        } finally {
            lock.unlock();
        }
    }

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

//同上面的put方法,只不过可以指定等待的时间
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)
                    return false;
                nanos = notFull.awaitNanos(nanos);
            }
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }

public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }


 private void enqueue(E x) {
        final Object[] items = this.items;
        //保存到putIndex索引处
        items[putIndex] = x;
        //数组满了,将其重置为0
        if (++putIndex == items.length)
            putIndex = 0;
        //数组元素个数增加    
        count++;
        //唤醒因为队列是空的而等待的线程
        notEmpty.signal();
    }

private static void checkNotNull(Object v) {
        if (v == null)
            throw new NullPointerException();
    }

4、poll / take / peek

     这几个方法都是获取队列顶的元素,具体说明如下:

  • poll方法有两个重载版本,第一个版本,如果队列是空的,返回null,否则移除并返回队列头部元素;另一个带时间参数的版本,如果栈为空则等待,可以指定等待的时间,如果等待超时了则返回null,如果被中断了则抛出异常,否则移除并返回栈顶元素
  • take方法同带时间参数的poll方法,但是不能指定等待时间,会一直等待直到队列中有元素为止,然后移除并返回栈顶元素
  • peek方法只是返回队列头部元素,不移除
public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            //如果为空,返回null,否则取出一个元素
            return (count == 0) ? null : dequeue();
        } finally {
            lock.unlock();
        }
    }

    public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            //如果空的,则等待
            while (count == 0)
                notEmpty.await();
            //取出一个元素   
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

    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; //等待超时,返回null
                //数组为空,等待    
                nanos = notEmpty.awaitNanos(nanos);
            }
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

    public E peek() {
        final ReentrantLock lock = this.lock;
   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值