持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第4天,点击查看活动详情
特点
ArrayBlockingQueue 也叫做数组阻塞队列,底层使用的是数组。
- 有界的阻塞数组,容量一旦创建,后续大小无法修改
- 元素是有顺序的,按照先入先出进行排序,从队尾插入数据数据,从队头拿数据
- 队列满时,往队列中 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开始插入