ArrayBlockingQueue源码分析-新增和获取数据

90 阅读2分钟

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

新增

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

private void enqueue(E x) {
    // assert lock.getHoldCount() == 1;
    // assert items[putIndex] == null;
    final Object[] items = this.items;
    items[putIndex] = x;
    if (++putIndex == items.length)
        putIndex = 0;
    count++;
    notEmpty.signal();
}

checkNotNull(e); 元素不能为空

while (count == items.length) notFull.await();队列如果是满的,就无限等待, 一直等待队列中有数据被拿走时,自己被唤醒

items[putIndex] = x; putIndex 为本次插入的位置

if (++putIndex == items.length) putIndex = 0; ++ putIndex 计算下次插入的位置,如果下次插入的位置,正好等于队尾,下次插入就从 0 开始

notEmpty.signal();唤醒因为队列空导致的等待线程

数据新增都会按照 putIndex 的位置进行新增,如果队列满,无限阻塞。主要新增分为了两种情况:

  1. 如果新增的位置居中,则直接新增.
  2. 如果新增的位置到队尾了,则下次新增时就要从头开始

获取数据

public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue();
    } finally {
        lock.unlock();
    }
}

private E dequeue() {
    final Object[] items = this.items;
    E x = (E) items[takeIndex];
    items[takeIndex] = null;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

while (count == 0) notEmpty.await();如果队列为空,无限等待,直到队列中有数据被 put 后,自己被唤醒

return dequeue();从队列中拿数据

E x = (E) items[takeIndex]; takeIndex 代表本次拿数据的位置,是上一次拿数据时计算好的

items[takeIndex] = null; 帮助 gc

if (++takeIndex == items.length) takeIndex = 0; ++ takeIndex 计算下次拿数据的位置,如果正好等于队尾的话,下次就从 0 开始拿数据

count--; 队列实际大小减 1

notFull.signal(); 唤醒被队列满所阻塞的线程

每次获取数据的位置就是 takeIndex 的位置,在找到本次应该获取的数据之后,会把 takeIndex 加 1,计算下次拿数据时的索引位置,有个特别的情况是:如果本次拿数据的位置已经是队尾了,那么下次拿数据的位置就要从头开始,就是从 0 开始了。