Java - ArrayBlockingQueue设计原理

ArrayBlockingQueueLinkedBlockingQueue都是BlockingQueue的实现,从名字就可以看出ArrayBlockingQueue底层是基于数组的,LinkedBlockingQueue底层是基于链表的。
ArrayBlockingQueue比较特殊,它的链表是一个环形链表,内部维护了putIndextakeIndex索引,用来指定puttake的位置,如下所示:

Java - ArrayBlockingQueue设计原理_第1张图片

这么设计的好处是通过移动指针来替代数组元素移动,极大的减少了数组移动带来的性能损耗。

下面将通过源码介绍:

1. put方法

加锁和阻塞机制与LinkedBlockingQueue相同,主要关注enqueue方法

public void put(E e) throws InterruptedException {
    checkNotNull(e);
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length) // 数据满了的时候,不会进入enqueue方法
            notFull.await();
        enqueue(e);
    } finally {
        lock.unlock();
    }
}
  • enqueue
  1. items[putIndex] = x;说明内部数组记录一个putIndex索引,用于添加元素。
  2. if (++putIndex == items.length),添加之后进行++putIndex指针后移,并当指针越界时重置为0位置,形成环形链表。
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();
}
2. take方法
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0)
            notEmpty.await();
        return dequeue(); // 执行take
    } finally {
        lock.unlock();
    }
}
  • dequeue
    记录takeIndex位置,进行take操作
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;
    if (++takeIndex == items.length)
        takeIndex = 0;
    count--;
    if (itrs != null)
        itrs.elementDequeued();
    notFull.signal();
    return x;
}

你可能感兴趣的:(Java - ArrayBlockingQueue设计原理)