JDK 8 ArrayBlockingQueue 源码详解(详细注释版)
1. 类定义和基本属性
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// 序列化版本号
private static final long serialVersionUID = -817911632652898426L;
/**
* 底层存储数组,用于存放队列元素
* 使用final修饰,一旦初始化后不能改变引用
* 数组大小固定,体现了有界队列的特性
*/
final Object[] items;
/**
* 下一个要取出元素的索引位置(队首)
* 通过取模运算实现循环数组的效果
* 当takeIndex等于items.length时,会回到0
*/
int takeIndex;
/**
* 下一个要插入元素的索引位置(队尾)
* 通过取模运算实现循环数组的效果
* 当putIndex等于items.length时,会回到0
*/
int putIndex;
/**
* 队列中当前元素的数量
* 用于判断队列是否为空或满
* 通过count可以避免复杂的索引比较
*/
int count;
/**
* 用于保证线程安全的可重入锁
* 所有操作都需要获取这个锁才能执行
* 保证了队列操作的原子性和可见性
*/
final ReentrantLock lock;
/**
* 等待获取元素的条件队列
* 当队列为空时,想要取出元素的线程会在这个条件上等待
* 当有新元素入队时,会通知等待的线程
*/
private final Condition notEmpty;
/**
* 等待插入元素的条件队列
* 当队列已满时,想要插入元素的线程会在这个条件上等待
* 当有元素出队时,会通知等待的线程
*/
private final Condition notFull;
/**
* 队列是否采用公平策略
* true表示公平锁,按照等待时间顺序获取锁
* false表示非公平锁,允许插队,但性能更好
*/
final boolean fair;
/**
* 检查索引是否有效
* 用于确保索引在数组范围内
* @param i 要检查的索引
* @param size 数组大小
*/
static void checkBounds(int i, int size) {
if (i < 0 || i >= size)
throw new IndexOutOfBoundsException("Index: " + i + ", Size: " + size);
}
/**
* 将指定索引位置的元素转换为泛型类型
* 由于数组存储的是Object类型,需要进行类型转换
* @param items 数组
* @param i 索引位置
* @return 泛型类型的元素
*/
@SuppressWarnings("unchecked")
static <E> E itemAt(Object[] items, int i) {
return (E) items[i];
}
2. 构造方法(详细注释)
/**
* 指定容量的构造方法
* 创建一个指定容量的ArrayBlockingQueue
* @param capacity 队列容量,必须大于0
* @throws IllegalArgumentException 如果capacity小于等于0
*
* 构造过程:
* 1. 验证容量参数的有效性
* 2. 创建指定大小的数组
* 3. 创建非公平锁
* 4. 创建两个条件队列
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false); // 默认使用非公平锁
}
/**
* 指定容量和公平策略的构造方法
* @param capacity 队列容量,必须大于0
* @param fair 是否使用公平锁
* @throws IllegalArgumentException 如果capacity小于等于0
*
* 公平性说明:
* - 公平锁:线程按照请求锁的顺序获得锁,避免饥饿现象
* - 非公平锁:允许插队,性能更好但可能导致某些线程长时间等待
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException(); // 容量必须大于0
this.items = new Object[capacity]; // 创建存储数组
lock = new ReentrantLock(fair); // 创建指定公平性的锁
notEmpty = lock.newCondition(); // 创建非空条件
notFull = lock.newCondition(); // 创建非满条件
this.fair = fair; // 保存公平性设置
}
/**
* 指定初始集合的构造方法
* 创建一个包含指定集合元素的ArrayBlockingQueue
* @param capacity 队列容量
* @param fair 是否使用公平锁
* @param c 包含初始元素的集合
* @throws IllegalArgumentException 如果capacity小于集合大小
* @throws NullPointerException 如果c为null
*
* 初始化过程:
* 1. 验证容量是否足够容纳初始集合
* 2. 将集合元素逐个添加到队列中
* 3. 设置队列的初始状态
*/
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair); // 先调用基本构造方法
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁,确保线程安全
try {
int i = 0;
try {
// 将集合中的元素逐个添加到队列中
for (E e : c) {
checkNotNull(e); // 检查元素不为null
items[i++] = e; // 存储元素
}
} catch (ArrayIndexOutOfBoundsException ex) {
// 如果集合大小超过容量,抛出异常
throw new IllegalArgumentException();
}
count = i; // 设置元素数量
putIndex = (i == capacity) ? 0 : i; // 设置插入位置
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 指定初始集合的构造方法(默认非公平)
* @param capacity 队列容量
* @param c 包含初始元素的集合
*/
public ArrayBlockingQueue(int capacity, Collection<? extends E> c) {
this(capacity, false, c); // 调用三参数构造方法
}
/**
* 检查元素不为null
* ArrayBlockingQueue不允许存储null元素
* @param v 要检查的元素
* @throws NullPointerException 如果v为null
*/
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
3. 核心入队方法(详细注释)
/**
* 在队尾插入元素(非阻塞)
* 如果队列已满,直接返回false
* @param e 要插入的元素
* @return 如果成功插入返回true,否则返回false
* @throws NullPointerException 如果e为null
*
* 操作流程:
* 1. 获取锁
* 2. 检查队列是否已满
* 3. 如果未满,插入元素并更新状态
* 4. 通知等待取元素的线程
* 5. 释放锁
*/
public boolean offer(E e) {
checkNotNull(e); // 检查元素不为null
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
if (count == items.length) // 如果队列已满
return false; // 直接返回false
else {
enqueue(e); // 插入元素
return true; // 返回true
}
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 在队尾插入元素(可超时阻塞)
* 如果队列已满,等待指定时间直到有空间或超时
* @param e 要插入的元素
* @param timeout 等待时间
* @param unit 时间单位
* @return 如果成功插入返回true,否则返回false
* @throws InterruptedException 如果线程被中断
* @throws NullPointerException 如果e为null
*
* 阻塞机制:
* 1. 如果队列未满,直接插入
* 2. 如果队列已满,等待指定时间
* 3. 在等待期间可被中断
* 4. 超时后如果仍未插入成功,返回false
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e); // 检查元素不为null
long nanos = unit.toNanos(timeout); // 转换为纳秒
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 可中断地获取锁
try {
while (count == items.length) { // 如果队列已满
if (nanos <= 0) // 如果超时时间已到
return false; // 返回false
// 在notFull条件上等待指定时间
nanos = notFull.awaitNanos(nanos);
}
enqueue(e); // 插入元素
return true; // 返回true
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 在队尾插入元素(阻塞)
* 如果队列已满,一直等待直到有空间
* @param e 要插入的元素
* @throws InterruptedException 如果线程被中断
* @throws NullPointerException 如果e为null
*
* 阻塞特性:
* 1. 如果队列未满,直接插入
* 2. 如果队列已满,无限期等待
* 3. 在等待期间可被中断
* 4. 有空间时自动唤醒并插入
*/
public void put(E e) throws InterruptedException {
checkNotNull(e); // 检查元素不为null
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 可中断地获取锁
try {
while (count == items.length) // 如果队列已满
notFull.await(); // 在notFull条件上等待
enqueue(e); // 插入元素
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 实际的入队操作
* 在已获得锁的情况下执行插入操作
* @param e 要插入的元素
*
* 循环数组实现:
* 1. 将元素存储到putIndex位置
* 2. 更新putIndex(循环递增)
* 3. 增加元素计数
* 4. 通知等待取元素的线程
*/
private void enqueue(E e) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = e; // 在putIndex位置存储元素
if (++putIndex == items.length) putIndex = 0; // 循环递增putIndex
count++; // 增加元素计数
notEmpty.signal(); // 通知等待取元素的线程
}
4. 核心出队方法(详细注释)
/**
* 从队首取出元素(非阻塞)
* 如果队列为空,直接返回null
* @return 队首元素,如果队列为空返回null
*
* 操作流程:
* 1. 获取锁
* 2. 检查队列是否为空
* 3. 如果非空,取出元素并更新状态
* 4. 通知等待插入元素的线程
* 5. 释放锁
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
return (count == 0) ? null : dequeue(); // 如果非空则取出元素
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 从队首取出元素(可超时阻塞)
* 如果队列为空,等待指定时间直到有元素或超时
* @param timeout 等待时间
* @param unit 时间单位
* @return 队首元素,如果超时返回null
* @throws InterruptedException 如果线程被中断
*
* 阻塞机制:
* 1. 如果队列非空,直接取出元素
* 2. 如果队列为空,等待指定时间
* 3. 在等待期间可被中断
* 4. 超时后如果仍为空,返回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; // 返回null
// 在notEmpty条件上等待指定时间
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue(); // 取出元素
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 从队首取出元素(阻塞)
* 如果队列为空,一直等待直到有元素
* @return 队首元素
* @throws InterruptedException 如果线程被中断
*
* 阻塞特性:
* 1. 如果队列非空,直接取出元素
* 2. 如果队列为空,无限期等待
* 3. 在等待期间可被中断
* 4. 有元素时自动唤醒并取出
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); // 可中断地获取锁
try {
while (count == 0) // 如果队列为空
notEmpty.await(); // 在notEmpty条件上等待
return dequeue(); // 取出元素
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 实际的出队操作
* 在已获得锁的情况下执行取出操作
* @return 取出的元素
*
* 循环数组实现:
* 1. 从takeIndex位置取出元素
* 2. 清空该位置的引用(帮助GC)
* 3. 更新takeIndex(循环递增)
* 4. 减少元素计数
* 5. 通知等待插入元素的线程
*/
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; // 清空引用,帮助GC
if (++takeIndex == items.length) takeIndex = 0; // 循环递增takeIndex
count--; // 减少元素计数
if (itrs != null)
itrs.elementDequeued(); // 更新迭代器状态
notFull.signal(); // 通知等待插入元素的线程
return x; // 返回取出的元素
}
/**
* 获取但不移除队首元素
* @return 队首元素,如果队列为空返回null
*
* 查看操作特点:
* 1. 不改变队列状态
* 2. 非阻塞操作
* 3. 线程安全
*/
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
return itemAt(items, takeIndex); // 返回队首元素
} finally {
lock.unlock(); // 释放锁
}
}
5. 批量操作方法(详细注释)
/**
* 批量添加元素到队列中
* 将指定集合中的元素逐个添加到队列尾部
* @param c 包含要添加元素的集合
* @return 如果成功添加所有元素返回true,否则返回false
* @throws NullPointerException 如果c为null
* @throws IllegalArgumentException 如果c为空
*
* 批量添加特点:
* 1. 原子性:要么全部添加成功,要么全部失败
* 2. 阻塞性:如果队列空间不足会阻塞
* 3. 中断性:可被线程中断
*/
public boolean addAll(Collection<? extends E> c) {
checkNotNull(c); // 检查集合不为null
if (c == this)
throw new IllegalArgumentException(); // 不能添加自身
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
int n = c.size(); // 获取集合大小
if (n == 0)
throw new IllegalArgumentException(); // 集合不能为空
if (n > items.length - count) // 如果空间不足
return false; // 返回false
Object[] src = c.toArray(); // 转换为数组
if (src.getClass() != Object[].class)
src = Arrays.copyOf(src, src.length, Object[].class);
int firstSuffix = items.length - putIndex; // 第一段可插入数量
if (n <= firstSuffix) {
// 如果所有元素都能在第一段插入
System.arraycopy(src, 0, items, putIndex, n);
} else {
// 如果需要分两段插入
System.arraycopy(src, 0, items, putIndex, firstSuffix);
System.arraycopy(src, firstSuffix, items, 0, n - firstSuffix);
}
// 更新putIndex和count
int oldPutIndex = putIndex;
putIndex += n;
if (putIndex >= items.length) putIndex -= items.length;
count += n;
// 通知等待取元素的线程
if (count > 0) {
for (int i = 0; i < n; i++) {
notEmpty.signal(); // 通知n次
}
}
return true; // 返回true
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 批量取出元素到指定集合中
* 从队列中取出最多maxElements个元素添加到指定集合
* @param c 用于存储取出元素的集合
* @param maxElements 最大取出元素数量
* @return 实际取出的元素数量
* @throws UnsupportedOperationException 如果c不支持添加操作
* @throws ClassCastException 如果元素类型不兼容
* @throws NullPointerException 如果c为null
* @throws IllegalArgumentException 如果c是当前队列
*
* 批量取出特点:
* 1. 非阻塞操作
* 2. 原子性:一次性取出多个元素
* 3. 线程安全
*/
public int drainTo(Collection<? super E> c, int maxElements) {
checkNotNull(c); // 检查集合不为null
if (c == this)
throw new IllegalArgumentException(); // 不能添加到自身
if (maxElements <= 0)
return 0; // 如果最大数量小于等于0,返回0
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
int n = Math.min(maxElements, count); // 实际取出数量
int take = takeIndex;
int i = 0;
try {
while (i < n) {
@SuppressWarnings("unchecked")
E x = (E) items[take]; // 取出元素
c.add(x); // 添加到指定集合
items[take] = null; // 清空引用
if (++take == items.length) take = 0; // 循环递增
i++;
}
return n; // 返回实际取出数量
} finally {
// 更新状态
if (i > 0) {
takeIndex = take;
count -= i;
if (itrs != null) {
if (count == 0)
itrs.queueIsEmpty();
else if (i > take)
itrs.takeIndexWrapped();
}
// 通知等待插入元素的线程
for (; i > 0; i--)
notFull.signal();
}
}
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 批量取出所有元素到指定集合中
* @param c 用于存储取出元素的集合
* @return 实际取出的元素数量
*/
public int drainTo(Collection<? super E> c) {
return drainTo(c, Integer.MAX_VALUE); // 取出所有元素
}
6. 查询和状态方法(详细注释)
/**
* 返回队列中元素的数量
* @return 队列中元素的数量
*
* size()操作特点:
* 1. 线程安全:通过锁保护
* 2. 快速操作:直接返回count字段
* 3. 瞬时值:反映调用时刻的状态
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
return count; // 返回元素数量
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 返回队列的剩余容量
* @return 队列还能容纳的元素数量
*
* remainingCapacity()特点:
* 1. 线程安全:通过锁保护
* 2. 动态计算:总容量减去当前元素数量
* 3. 瞬时值:反映调用时刻的状态
*/
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
return items.length - count; // 返回剩余容量
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 判断队列是否为空
* @return 如果队列为空返回true,否则返回false
*
* isEmpty()特点:
* 1. 线程安全:通过锁保护
* 2. 快速判断:检查count是否为0
* 3. 瞬时判断:反映调用时刻的状态
*/
public boolean isEmpty() {
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
return count == 0; // 判断是否为空
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 判断队列是否包含指定元素
* @param o 要查找的元素
* @return 如果包含返回true,否则返回false
*
* contains()特点:
* 1. 线程安全:通过锁保护
* 2. 全遍历:需要遍历整个队列
* 3. 时间复杂度:O(n)
*/
public boolean contains(Object o) {
if (o == null) return false; // null元素不包含
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
if (count > 0) {
int i = takeIndex; // 从队首开始
int k = 0;
while (k++ < count) {
if (o.equals(items[i])) // 比较元素
return true;
if (++i == items.length) i = 0; // 循环递增
}
}
return false; // 没有找到
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 移除队列中的指定元素
* @param o 要移除的元素
* @return 如果成功移除返回true,否则返回false
*
* remove()特点:
* 1. 线程安全:通过锁保护
* 2. 全遍历:需要遍历整个队列
* 3. 时间复杂度:O(n)
* 4. 只移除第一个匹配的元素
*/
public boolean remove(Object o) {
if (o == null) return false; // null元素不能移除
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
if (count > 0) {
int i = takeIndex; // 从队首开始
int k = 0;
while (k++ < count) {
if (o.equals(items[i])) { // 找到匹配元素
removeAt(i); // 移除指定位置的元素
return true; // 返回true
}
if (++i == items.length) i = 0; // 循环递增
}
}
return false; // 没有找到
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 移除指定位置的元素
* 在已获得锁的情况下执行移除操作
* @param removeIndex 要移除元素的索引
*
* 移除操作特点:
* 1. 需要移动后续元素
* 2. 更新队列状态
* 3. 通知等待线程
*/
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) {
// 如果移除的是队首元素
items[takeIndex] = null; // 清空引用
if (++takeIndex == items.length) takeIndex = 0; // 更新takeIndex
count--; // 减少计数
if (itrs != null)
itrs.elementDequeued(); // 更新迭代器
} else {
// 如果移除的是中间或队尾元素
int i = removeIndex;
int putIndex = this.putIndex;
if (i < putIndex) {
// 如果在putIndex之前,直接移动
System.arraycopy(items, i + 1, items, i, putIndex - i - 1);
} else {
// 如果在putIndex之后,需要分段移动
System.arraycopy(items, i + 1, items, i, items.length - i - 1);
items[items.length - 1] = items[0];
System.arraycopy(items, 1, items, 0, putIndex);
}
items[putIndex - 1] = null; // 清空最后一个位置
this.putIndex = putIndex - 1; // 更新putIndex
count--; // 减少计数
}
notFull.signal(); // 通知等待插入的线程
}
7. 迭代器实现(详细注释)
/**
* 返回队列的迭代器
* @return 队列的迭代器
*
* 迭代器特点:
* 1. 弱一致性:反映创建时的状态
* 2. 不抛出ConcurrentModificationException
* 3. 线程安全:通过锁保护
* 4. 支持remove()操作
*/
public Iterator<E> iterator() {
return new Itr(); // 返回自定义迭代器
}
/**
* ArrayBlockingQueue的迭代器实现
*/
private class Itr implements Iterator<E> {
/**
* 当前迭代位置的游标
*/
private int cursor;
/**
* 上次返回元素的索引
*/
private int lastRet;
/**
* 创建迭代器时的元素快照
*/
private Object[] snapshot;
/**
* 构造方法
*/
Itr() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock(); // 获取锁
try {
// 创建元素快照
int size = count;
snapshot = new Object[size];
if (size > 0) {
int i = takeIndex;
for (int k = 0; k < size; k++) {
snapshot[k] = items[i];
if (++i == items.length) i = 0;
}
}
cursor = 0;
lastRet = -1;
} finally {
lock.unlock(); // 释放锁
}
}
/**
* 判断是否还有下一个元素
* @return 如果还有下一个元素返回true,否则返回false
*/
public boolean hasNext() {
return cursor < snapshot.length;
}
/**
* 获取下一个元素
* @return 下一个元素
* @throws NoSuchElementException 如果没有下一个元素
*/
public E next() {
if (cursor >= snapshot.length)
throw new NoSuchElementException();
lastRet = cursor;
@SuppressWarnings("unchecked")
E item = (E) snapshot[cursor++];
return item;
}
/**
* 移除上次返回的元素
* @throws IllegalStateException 如果没有可移除的元素
*/
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock(); // 获取锁
try {
// 在原队列中查找并移除对应元素
Object obj = snapshot[lastRet];
int size = count;
int i = takeIndex;
int k = 0;
while (k++ < size) {
if (obj.equals(items[i])) {
removeAt(i);
break;
}
if (++i == items.length) i = 0;
}
// 更新快照
int newSize = count;
if (newSize != size) {
Object[] newSnapshot = new Object[newSize];
int newTakeIndex = takeIndex;
for (int j = 0; j < newSize; j++) {
newSnapshot[j] = items[newTakeIndex];
if (++newTakeIndex == items.length) newTakeIndex = 0;
}
snapshot = newSnapshot;
cursor = lastRet;
} else {
cursor--;
}
lastRet = -1;
} finally {
lock.unlock(); // 释放锁
}
}
}
8. 转换和克隆方法(详细注释)
/**
* 转换为数组
* @return 包含队列所有元素的数组
*
* toArray()特点:
* 1. 线程安全:通过锁保护
* 2. 保持顺序:按照队列的FIFO顺序
* 3. 瞬时快照:反映调用时刻的状态
*/
public Object[] toArray() {
Object[] a;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
int size = count;
a = new Object[size];
if (size > 0) {
int i = takeIndex;
for (int k = 0; k < size; k++) {
a[k] = items[i];
if (++i == items.length) i = 0;
}
}
} finally {
lock.unlock(); // 释放锁
}
return a;
}
/**
* 转换为指定类型的数组
* @param a 指定类型的数组
* @return 转换后的数组
* @throws ArrayStoreException 如果数组类型不兼容
* @throws NullPointerException 如果a为null
*/
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); // 获取锁
try {
int size = count;
if (a.length < size)
a = (T[])java.lang.reflect.Array.newInstance(
a.getClass().getComponentType(), size);
if (size > 0) {
int i = takeIndex;
for (int k = 0; k < size; k++) {
a[k] = (T) items[i];
if (++i == items.length) i = 0;
}
}
if (a.length > size)
a[size] = null;
} finally {
lock.unlock(); // 释放锁
}
return a;
}
/**
* 克隆队列
* @return 克隆后的队列
*
* clone()特点:
* 1. 浅克隆:只克隆队列结构,不克隆元素
* 2. 独立状态:新队列有自己的锁和条件
* 3. 相同元素:包含相同的元素引用
*/
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayBlockingQueue<E> other = (ArrayBlockingQueue<E>) super.clone();
other.items = Arrays.copyOf(items, items.length);
other.lock = new ReentrantLock(fair);
other.notEmpty = other.lock.newCondition();
other.notFull = other.lock.newCondition();
other.takeIndex = takeIndex;
other.putIndex = putIndex;
other.count = count;
return other;
} catch (CloneNotSupportedException e) {
throw new InternalError();
}
}
9. ArrayBlockingQueue 的特点分析
核心设计理念:
/**
* ArrayBlockingQueue的核心设计思想:
*
* 1. 有界阻塞队列:
* - 固定容量,不能动态扩容
* - 当队列满时,插入操作会阻塞
* - 当队列空时,取出操作会阻塞
*
* 2. 循环数组实现:
* - 使用数组存储元素,通过索引循环使用
* - takeIndex指向队首,putIndex指向队尾
* - 通过count跟踪元素数量
*
* 3. 锁分离机制:
* - 使用单个ReentrantLock保护所有操作
* - 使用两个Condition分别处理空和满的状态
* - notEmpty条件用于等待元素
* - notFull条件用于等待空间
*
* 4. 阻塞机制:
* - put()和take()方法支持无限期阻塞
* - offer()和poll()方法支持超时阻塞
* - offer()和poll()方法支持非阻塞操作
*
* 5. 线程安全:
* - 所有操作都通过锁保护
* - 保证操作的原子性和可见性
* - 支持多个生产者和消费者
*
* 适用场景:
* - 生产者-消费者模式
* - 线程池任务队列
* - 流量控制和缓冲
* - 需要有界队列的场景
*/
性能特征分析:
/**
* ArrayBlockingQueue的性能特征:
*
* 时间复杂度:
* - offer(e): O(1) - 非阻塞插入
* - put(e): O(1) 平均,O(∞) 最坏(阻塞等待)
* - poll(): O(1) - 非阻塞取出
* - take(): O(1) 平均,O(∞) 最坏(阻塞等待)
* - size(): O(1) - 直接返回count
* - contains(o): O(n) - 需要遍历队列
* - remove(o): O(n) - 需要遍历并移动元素
*
* 空间复杂度:
* - O(capacity) - 固定大小的数组
* - 额外的锁和条件对象开销
*
* 并发特性:
* - 单锁机制:所有操作使用同一个锁
* - 阻塞操作:支持生产者和消费者的协调
* - 公平性:可选择公平或非公平锁
* - 内存一致性:通过锁保证可见性
*
* 锁竞争:
* - 高并发下可能有锁竞争
* - 生产者和消费者共享同一把锁
* - 可能影响吞吐量
*
* 内存使用:
* - 固定内存占用
* - 不会动态扩容
* - 队列满时可能阻塞生产者
*/
10. 使用示例和最佳实践
/**
* 使用示例:
*
* // 基本使用
* ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
*
* // 生产者线程
* Thread producer = new Thread(() -> {
* try {
* for (int i = 0; i < 100; i++) {
* String item = "item-" + i;
* queue.put(item); // 阻塞插入
* System.out.println("Produced: " + item);
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* // 消费者线程
* Thread consumer = new Thread(() -> {
* try {
* while (true) {
* String item = queue.take(); // 阻塞取出
* System.out.println("Consumed: " + item);
* Thread.sleep(100); // 模拟处理时间
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
* });
*
* producer.start();
* consumer.start();
*
* // 线程池使用示例
* ExecutorService executor = Executors.newFixedThreadPool(5);
* ArrayBlockingQueue<Runnable> taskQueue = new ArrayBlockingQueue<>(100);
*
* // 提交任务
* for (int i = 0; i < 1000; i++) {
* final int taskId = i;
* executor.submit(() -> {
* System.out.println("Task " + taskId + " executed");
* });
* }
*
* 最佳实践:
*
* 1. 合理设置队列容量:
* // 根据系统负载和处理能力设置合适容量
* int capacity = Runtime.getRuntime().availableProcessors() * 2;
* ArrayBlockingQueue<Task> queue = new ArrayBlockingQueue<>(capacity);
*
* 2. 使用非阻塞操作避免死锁:
* // 在某些场景下使用非阻塞操作
* if (queue.offer(task)) {
* System.out.println("Task added successfully");
* } else {
* System.out.println("Queue is full, task rejected");
* // 处理拒绝策略
* }
*
* 3. 设置合理的超时时间:
* // 避免无限期等待
* try {
* Task task = queue.poll(1, TimeUnit.SECONDS);
* if (task != null) {
* processTask(task);
* } else {
* System.out.println("No task available");
* }
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt();
* }
*
* 4. 处理中断异常:
* // 正确处理InterruptedException
* try {
* Task task = queue.take();
* processTask(task);
* } catch (InterruptedException e) {
* Thread.currentThread().interrupt(); // 恢复中断状态
* System.out.println("Consumer interrupted");
* }
*
* 5. 监控队列状态:
* // 定期监控队列使用情况
* int size = queue.size();
* int remaining = queue.remainingCapacity();
* double usage = (double) size / (size + remaining);
* System.out.println("Queue usage: " + String.format("%.2f%%", usage * 100));
*
* 6. 批量操作提高效率:
* // 使用批量操作减少锁竞争
* List<Task> tasks = new ArrayList<>();
* int count = queue.drainTo(tasks, 10); // 批量取出最多10个任务
* for (Task task : tasks) {
* processTask(task);
* }
*
* 7. 选择合适的公平性:
* // 高并发场景下考虑使用非公平锁提高性能
* ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(100, false);
*
* 8. 避免队列过载:
* // 实现背压机制
* if (queue.remainingCapacity() < 10) {
* System.out.println("Queue is nearly full, slowing down production");
* Thread.sleep(1000); // 暂停生产
* }
*/
11. 与其他阻塞队列的比较
/**
* ArrayBlockingQueue vs LinkedBlockingQueue vs SynchronousQueue:
*
* ArrayBlockingQueue:
* - 有界队列,固定容量
* - 使用数组存储,内存占用固定
* - 单锁机制,生产者消费者共享锁
* - FIFO顺序,支持公平性选择
* - 适合需要有界缓冲的场景
*
* LinkedBlockingQueue:
* - 可选有界,支持无界
* - 使用链表存储,动态内存分配
* - 双锁机制,生产者消费者独立锁
* - FIFO顺序
* - 适合高并发场景
*
* SynchronousQueue:
* - 容量为0,直接传递
* - 不存储元素,生产者消费者直接配对
* - 最低延迟,最高吞吐量
* - 适合直接传递的场景
*
* PriorityBlockingQueue:
* - 无界优先级队列
* - 按优先级排序
* - 适合需要优先级处理的场景
*
* DelayQueue:
* - 无界延迟队列
* - 只有延迟到期的元素才能取出
* - 适合定时任务调度
*
* 选择建议:
* - 需要有界缓冲:ArrayBlockingQueue
* - 高并发场景:LinkedBlockingQueue
* - 直接传递:SynchronousQueue
* - 优先级处理:PriorityBlockingQueue
* - 延迟处理:DelayQueue
*/
12. 总结
ArrayBlockingQueue 的核心特性:
-
有界阻塞队列:
- 固定容量,不能动态扩容
- 当队列满时阻塞生产者
- 当队列空时阻塞消费者
-
循环数组实现:
- 使用数组存储元素
- 通过索引循环使用数组空间
- takeIndex和putIndex管理队首队尾
-
锁分离机制:
- 单个ReentrantLock保护所有操作
- 两个Condition分别处理空和满状态
- 支持公平和非公平锁选择
-
多种阻塞策略:
- put()/take():无限期阻塞
- offer()/poll():超时阻塞
- offer()/poll():非阻塞操作
-
线程安全:
- 所有操作都通过锁保护
- 保证原子性和可见性
- 支持多个生产者和消费者
适用场景:
- 生产者-消费者模式
- 线程池任务队列
- 流量控制和缓冲
- 需要有界队列的场景
- 需要阻塞特性的队列操作
注意事项:
- 容量固定,需要合理设置
- 单锁机制可能影响高并发性能
- 不允许存储null元素
- 迭代器是弱一致性的
- 队列满时生产者会被阻塞
性能优化建议:
- 根据业务需求合理设置队列容量
- 选择合适的公平性策略
- 正确处理中断异常
- 使用批量操作减少锁竞争
- 监控队列使用情况
- 实现合适的拒绝策略
- 避免队列过载和饥饿现象

374

被折叠的 条评论
为什么被折叠?



