ArrayBlockingQueue

ArrayBlockingQueue
ArrayBlockingQueue,一个由数组实现的有界阻塞队列。该队列采用FIFO的原则对元素进行排序添加的,(删除添加可以理解为循环的数组添加在前删除在后追赶)。 ArrayBlockingQueue为有界且固定,其大小在构造时由构造函数来决定,确认之后就不能再改变了。支持公平策略

定义

ArrayBlockingQueue内部使用可重入锁ReentrantLock + Condition来完成多线程环境的并发操作。

1
2
3
4
5
6
7
8
9
10
11
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {
private static final long serialVersionUID = -817911632652898426L;
final Object[] items;//一个定长数组,维护ArrayBlockingQueue的元素
int takeIndex;//为ArrayBlockingQueue对首位置
int putIndex;//为ArrayBlockingQueue对尾位置
int count;//元素个数
final ReentrantLock lock;//重入锁,ArrayBlockingQueue出列入列都必须获取该锁,公用一个锁
private final Condition notEmpty;//出列条件,非空
private final Condition notFull;//入列条件,未满
transient ArrayBlockingQueue.Itrs itrs;
}

三个构造函数

1
2
3
4
5
6
7
8
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}

public ArrayBlockingQueue(int capacity, boolean fair) {}

public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {}

三个常用添加方法

  1. add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常。

    1
    Exception in thread "main" java.lang.IllegalStateException: Queue full
  2. put:添加元素到队列里,如果容量满了会阻塞直到容量不满。内部直接调用的enqueue

  3. offer:添加元素到队列里,添加成功返回true,添加失败返回false,下边的逻辑依旧可以执行。

    add内部调用offer(E e)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public boolean add(E e) {
    return super.add(e);
    }
    public boolean add(E e) {
    if (offer(e))
    return true;
    else
    throw new IllegalStateException("Queue full");
    }

    offer核心是enqueue方法,做了真正的入队操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public boolean offer(E e) {
    checkNotNull(e);//检查e是否为null,为null抛出异常。
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    if (count == items.length)
    return false;
    else {
    enqueue(e);
    return true;
    }
    } 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();//唤醒出队
    }

三个常用删除方法

  1. remove:删除队列头部元素,删除成功返回该元素,队列为空删除会抛出NoSuchElementException异常。

    1
    Exception in thread "main" java.util.NoSuchElementException
  2. take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除。

  3. poll:删除队列头部元素,如果队列为空,返回null,否则返回元素,下边逻辑依旧可以执行。可以传入时间,等待n时间,没有元素就返回null。

    remove底层最后调用了poll()takepoll底层最后执行的dequeue,二者区别仅在于poll返回null,take挂起。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    //take
    while (count == 0)
    notEmpty.await();
    return dequeue();

    //poll
    return (count == 0) ? null : dequeue();

    private E dequeue() {
    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();//内部迭代器需要移动元素位置,因为默认删除删的是头部,不处理迭代的话,迭代头部为null
    notFull.signal();
    return x;
    }

ArrayBlockingQueue
http://www.muzili.ren/2022/06/11/ArrayBlockingQueue/
作者
jievhaha
发布于
2022年6月11日
许可协议