ArrayBlockingQueue源码分析-构造方法

100 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情

特点

ArrayBlockingQueue 也叫做数组阻塞队列,底层使用的是数组。

  1. 有界的阻塞数组,容量一旦创建,后续大小无法修改
  2. 元素是有顺序的,按照先入先出进行排序,从队尾插入数据数据,从队头拿数据
  3. 队列满时,往队列中 put 数据会被阻塞,队列空时,往队列中拿数据也会被阻塞

源码属性

public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
        ...
        
        final Object[] items;
        
        int takeIndex;
        
        int putIndex;
        
        int count;
        
        final ReentrantLock lock;
        
        private final Condition notEmpty;
        
        private final Condition notFull;
        ...

}

final Object[] items; 队列存放在 object 的数组里面,数组大小必须在初始化的时候手动设置,没有默认大小

int takeIndex; 下次拿数据的时候的索引位置

int putIndex;下次放数据的索引位置

int count; 当前已有元素的大小

final ReentrantLock lock; 可重入的锁

private final Condition notEmpty; take的队列

private final Condition notFull; put的队列

其中takeIndex 和 putIndex,分别表示下次拿数据和下次放数据的索引,所以在新增数据和拿取数据时都无需进行多余的计算,可以直接知道应该新增到什么位置、从什么位置拿数据。

构造方法

public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    this.items = new Object[capacity];
    lock = new ReentrantLock(fair);
    // 队列不为空 Condition,在 put 成功时使用
    notEmpty = lock.newCondition();
    // 队列不满 Condition,在 take 成功时使用
    notFull =  lock.newCondition();
}

notEmpty = lock.newCondition();队列不为空 Condition,在 put 成功时使用

notFull = lock.newCondition();队列不满 Condition,在 take 成功时使用

其中fair参数主要用于设置读写锁是否公平。

有指定初始数据的构造方法:

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

int i = 0; 表示插入的位置

for (E e : c) { checkNotNull(e); items[i++] = e; } 如果c的大小超过了数组的大小会抛出异常

putIndex = (i == capacity) ? 0 : i; 如果插入的位置是队尾,则下次从0开始插入