JDK 8 ArrayBlockingQueue 源码详解(详细注释版)

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 的核心特性:

  1. 有界阻塞队列

    • 固定容量,不能动态扩容
    • 当队列满时阻塞生产者
    • 当队列空时阻塞消费者
  2. 循环数组实现

    • 使用数组存储元素
    • 通过索引循环使用数组空间
    • takeIndex和putIndex管理队首队尾
  3. 锁分离机制

    • 单个ReentrantLock保护所有操作
    • 两个Condition分别处理空和满状态
    • 支持公平和非公平锁选择
  4. 多种阻塞策略

    • put()/take():无限期阻塞
    • offer()/poll():超时阻塞
    • offer()/poll():非阻塞操作
  5. 线程安全

    • 所有操作都通过锁保护
    • 保证原子性和可见性
    • 支持多个生产者和消费者

适用场景:

  • 生产者-消费者模式
  • 线程池任务队列
  • 流量控制和缓冲
  • 需要有界队列的场景
  • 需要阻塞特性的队列操作

注意事项:

  • 容量固定,需要合理设置
  • 单锁机制可能影响高并发性能
  • 不允许存储null元素
  • 迭代器是弱一致性的
  • 队列满时生产者会被阻塞

性能优化建议:

  1. 根据业务需求合理设置队列容量
  2. 选择合适的公平性策略
  3. 正确处理中断异常
  4. 使用批量操作减少锁竞争
  5. 监控队列使用情况
  6. 实现合适的拒绝策略
  7. 避免队列过载和饥饿现象
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值