Table of Contents
概念
- queue(队列)是一种基础的数据结构,它只允许在一端进行入队列操作,另一端出队列操作,是一种先进先出(FIFO),或者按照其他定义的排序规则排列的线性表。
- collection(集合)是线性存储一组元素的数据结构。
- 空队列是指队列包含任何元素。
- 容量是指队列允许的元素个数上限
queue
队列是一种控制元素访问顺序的集合(比如先进先出)。除了继承 collection 接口的方法(queue 本身是接口),还提供添加元素,取出元素,检查元素等操作。Queueu 提供的方法基本上都包含以下两个部分:
- 如果操作失败,抛出异常
- 如果操作成功返回一个结果值。可能是数值,也可能是 boolean。
queue 添加元素时,如果到达队列的元素的数量上限,那么会添加失败。
queue 的排序规则一般有先进先出(FIFO),先进后出(LIFO),或者是根据一种比较规则排序并准守先进先出或者后进先出排序。
/**
* Inserts the specified element into this queue if it is possible to do so
* immediately without violating capacity restrictions, returning
* {@code true} upon success and throwing an {@code IllegalStateException}
* if no space is currently available.
* Collection 方法。往队列中添加一个元素。如果队列元素的个数已经达到数量的限制,那么该方法会抛出 IllegalStateException 异常;
* 否则返回 false
*
* @param e the element to add 元素对象
* @return {@code true} (as specified by {@link Collection#add}) 如果队列因为这次操作发生了改变,那么返回 true
* @throws IllegalStateException if the element cannot be added at this
* time due to capacity restrictions
* 如果本次操作没有成功添加元素,那么抛出 IllegalStateException 异常。比如队列已经达到最大允许的元素个数,
* 那么抛出 IllegalStateException 异常
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* 如果添加的元素的类型和队列要求的类型不一致,那么抛出 ClassCastException 异常
* @throws NullPointerException if the specified element is null and
* this queue does not permit null elements
* 如果队列不支持 null,那么添加 null 时抛出 NullPointerException。比如 LinkedList 就不禁止添加 null 元素。
* @throws IllegalArgumentException if some property of this element
* prevents it from being added to this queue
*
*/
boolean add(E e);
/**
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions.
* When using a capacity-restricted queue, this method is generally
* preferable to {@link #add}, which can fail to insert an element only
* by throwing an exception.
* 如果是长度限制的队列,那么 offer 和 add 类似。比如 AbstractQueue 的 add 方法的实现就是通过调用 offer 方法。
* 如果 offer 方法返回失败,那么抛出 IllegalStateException("Queue full")异常。
* @param e the element to add
* @return {@code true} if the element was added to this queue, else
* {@code false}
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null and
* this queue does not permit null elements
* @throws IllegalArgumentException if some property of this element
* prevents it from being added to this queue
*/
boolean offer(E e);
/**
* Retrieves and removes the head of this queue. This method differs
* from {@link #poll poll} only in that it throws an exception if this
* queue is empty.
*
* Collection 方法。检索队列第一个元素,将其从队列中删除,并将它错误本次方法的返回值返回。
*
* @return the head of this queue 队列的第一个元素
* @throws NoSuchElementException if this queue is empty 如果是空队列抛出 NoSuchElementException 异常。
*/
E remove();
/**
* Retrieves and removes the head of this queue,
* or returns {@code null} if this queue is empty.
*
* 检索队列第一个元素,并将它删除。如果是空队列,那么返回 null。
*
* @return the head of this queue, or {@code null} if this queue is empty
*/
E poll();
/**
* Retrieves, but does not remove, the head of this queue. This method
* differs from {@link #peek peek} only in that it throws an exception
* if this queue is empty.
*
* 检索并返回第一个元素。如果丢列是空队列,那么抛出 NoSuchElementException 异常。
*
* @return the head of this queue
* @throws NoSuchElementException if this queue is empty
*/
E element();
/**
* Retrieves, but does not remove, the head of this queue,
* or returns {@code null} if this queue is empty.
*
* 检索并返回第一个元素。如果是空队列,那么返回 Null
*
* @return the head of this queue, or {@code null} if this queue is empty
*/
E peek();
AbstractQueue
AbstractQueue 提供一些非常基础和简单的接口实现,尤其是针对 collection 中定义的添加元素、删除元素等。AbstractQueue 会将此类的方法转成接口 Queue 中定义的入队和出队的方法来实现。
public abstract class AbstractQueue<E>
extends AbstractCollection<E>
implements Queue<E> {
/**
* 添加一个元素到队列中。
* 使用 offer 方法实现添加元素。如果添加失败(offer 返回 false)则抛出 IllegalStateException 异常
*
* <p>This implementation returns <tt>true</tt> if <tt>offer</tt> succeeds,
* else throws an <tt>IllegalStateException</tt>.
*
* @param e the element to add
* @return <tt>true</tt> (as specified by {@link Collection#add})
* @throws IllegalStateException if the element cannot be added at this
* time due to capacity restrictions
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null and
* this queue does not permit null elements
* @throws IllegalArgumentException if some property of this element
* prevents it from being added to this queue
*/
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
/**
* 将队列的第一个元素出队列,并返回。
* 利用 poll 方法将第一个元素出队列。如果返回的元素是空时抛出 NoSuchElementException 异常
*
* @return the head of this queue
* @throws NoSuchElementException if this queue is empty
*/
public E remove() {
E x = poll();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
/**
* 返回队列第一个元素。
* 和 remove 的区别是不会将元素从队列中删除。利用 peek()方法返回队列第一个元素。
* 如果得到的元素是空时,抛出 NoSuchElementException 异常
*
*
* @return the head of this queue
* @throws NoSuchElementException if this queue is empty
*/
public E element() {
E x = peek();
if (x != null)
return x;
else
throw new NoSuchElementException();
}
/**
* 清空队列
*
*/
public void clear() {
while (poll() != null)
;
}
/**
* 将指定集合中的元素全部添加到队列中。
* 如果指定的集合(queue 继承集合)是队列本身,那么抛出 IllegalArgumentException 异常
* 如果在添加过程中,集合发生变化可能会引起未知的问题。
*
* @param c collection containing elements to be added to this queue
* @return <tt>true</tt> if this queue changed as a result of the call
* @throws ClassCastException if the class of an element of the specified
* collection prevents it from being added to this queue
* @throws NullPointerException if the specified collection contains a
* null element and this queue does not permit null elements,
* or if the specified collection is null
* @throws IllegalArgumentException if some property of an element of the
* specified collection prevents it from being added to this
* queue, or if the specified collection is this queue
* @throws IllegalStateException if not all the elements can be added at
* this time due to insertion restrictions
* @see #add(Object)
*/
public boolean addAll(Collection<? extends E> c) {
if (c == null)
throw new NullPointerException();
if (c == this)
throw new IllegalArgumentException();
boolean modified = false;
for (E e : c)
if (add(e))
modified = true;
return modified;
}
}
BlockingQueue
阻塞队列拥有当调用线程从空队列获取元素时将线程置为阻塞状态,直到有元素添加到队列中。阻塞队列将元素从队列中删除,并且将元素给到阻塞线程,并唤醒线程。线程调用阻塞队列添加元素时,如果队列已经达到允许的元素上限,那么阻塞线程。直到阻塞队列允许添加元素,阻塞队列将元素添加到阻塞队列中,并唤醒添加元素的线程。
阻塞队列不接受 null 元素。往队列中添加元素的方法,包括 add,put,offer,如果参数是 null,那么立即抛出空指针异常(NullPointerException)。
大多数的阻塞队列都是有容量限制的。如果超过这个容量限制就无法在不阻塞的情况下将元素添加到阻塞队列中。在没有明确指定阻塞队列容量大小的情况下,阻塞队列容量大小一般是 Integer.MAXVALUE
尽管阻塞队列主要一般用于生产者消费者场景而不是用做集合管理元素,但是依然实现了 Collection 接口,对外提供了集合相关的方法。除非明确不用于生产者消费者场景或者该场景的相关任务已经结束,否则谨慎使用集合相关的方法。
阻塞队列实现类实现的阻塞队列的接口要求都是原子操作,是线程安全的。但是集合类的批量接口,比如 addAll,containsAll,retainAll,remoeAll 除非是实现类做了特殊处理,否则可能不是原子操作。因此很可能出现批量操作过程中出错,比如 addAll 一个 10 个元素的集合出错,很可能添加进去了 5 个元素,而另外 5 个元素没有添加成功。
如果生产者已经不产生任何产品了,那么可能需要关闭队列。但是因为阻塞队列本身没有提供关闭方法(close or shutdown),所以需要实现类实现一个关闭的策略。通常这个策略是提供一个特殊元素,表示这是最后元素。当消费者获取到这个特殊元素后关闭队列。
一个最基本的生产者消费者
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
BlockingQueue 接口中文翻译
/**
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions, returning
* {@code true} upon success and throwing an
* {@code IllegalStateException} if no space is currently available.
* When using a capacity-restricted queue, it is generally preferable to
* use {@link #offer(Object) offer}.
*
* 如果没有达到容量限制,那么将元素添加到队列中,并返回 true;否则抛出 IllegalStateException 异常。
* 在有容量限制的队列中,add 方法通过调用 offer 方法实现添加元素的操作。
*
* @param e the element to add
* @return {@code true} (as specified by {@link Collection#add})
* @throws IllegalStateException if the element cannot be added at this
* time due to capacity restrictions
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
boolean add(E e);
/**
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions, returning
* {@code true} upon success and {@code false} if no space is currently
* available. When using a capacity-restricted queue, this method is
* generally preferable to {@link #add}, which can fail to insert an
* element only by throwing an exception.
*
* 如果添加元素时,队列没有达到容量上限,那么将元素添加到队列并返回 true;否则返回 false。
* 在有容量限制的队列中,add 方法通过调用 offer 方法来实现添加元素。如果 offer 返回 false,
* 那么抛出 IllegalArgumentException 异常
*
* @param e the element to add
* @return {@code true} if the element was added to this queue, else
* {@code false}
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
boolean offer(E e);
/**
* Inserts the specified element into this queue, waiting if necessary
* for space to become available.
*
* 将元素添加到队列中。如果队列已经达到容量上限,那么该操作将阻塞线程,知道队列中元素被消费,添加操作能够完成。
*
* @param e the element to add
* @throws InterruptedException if interrupted while waiting
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
void put(E e) throws InterruptedException;
/**
* Inserts the specified element into this queue, waiting up to the
* specified wait time if necessary for space to become available.
*
* 和 put 方法类似,比 put 方法增加了线程等待时间。如果超过等待时间,线程将被唤醒。
*
* @param e the element to add
* @param timeout how long to wait before giving up, in units of
* {@code unit}
* @param unit a {@code TimeUnit} determining how to interpret the
* {@code timeout} parameter
* @return {@code true} if successful, or {@code false} if
* the specified waiting time elapses before space is available
* @throws InterruptedException if interrupted while waiting
* @throws ClassCastException if the class of the specified element
* prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
* element prevents it from being added to this queue
*/
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException;
/**
* Retrieves and removes the head of this queue, waiting if necessary
* until an element becomes available.
*
* 从队列中获取元素。如果队列中没有元素可以出队列,那么线程将阻塞知道获得一个元素。
*
* @return the head of this queue
* @throws InterruptedException if interrupted while waiting
*/
E take() throws InterruptedException;
/**
* Retrieves and removes the head of this queue, waiting up to the
* specified wait time if necessary for an element to become available.
*
* 和 take 类似,增加了线程等待时间。
*
* @param timeout how long to wait before giving up, in units of
* {@code unit}
* @param unit a {@code TimeUnit} determining how to interpret the
* {@code timeout} parameter
* @return the head of this queue, or {@code null} if the
* specified waiting time elapses before an element is available
* @throws InterruptedException if interrupted while waiting
*/
E poll(long timeout, TimeUnit unit)
throws InterruptedException;
/**
* Returns the number of additional elements that this queue can ideally
* (in the absence of memory or resource constraints) accept without
* blocking, or {@code Integer.MAX_VALUE} if there is no intrinsic
* limit.
*
* 返回可用容量,即容量上限 - 队列中的元素个数。
*
* <p>Note that you <em>cannot</em> always tell if an attempt to insert
* an element will succeed by inspecting {@code remainingCapacity}
* because it may be the case that another thread is about to
* insert or remove an element.
*
* 由于其他线程同时做添加元素和获取元素的操作导致阻塞,该方法可能无法立即返回结果。
*
* @return the remaining capacity
*/
int remainingCapacity();
/**
* Removes a single instance of the specified element from this queue,
* if it is present. More formally, removes an element {@code e} such
* that {@code o.equals(e)}, if this queue contains one or more such
* elements.
* Returns {@code true} if this queue contained the specified element
* (or equivalently, if this queue changed as a result of the call).
*
* 从队列中删除元素。如果队列包含该元素,那么将元素从队列中删除,并返回 true;
* 如果队列没有给定的元素,那么返回 false。
*
* @param o element to be removed from this queue, if present
* @return {@code true} if this queue changed as a result of the call
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
* (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
* (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
boolean remove(Object o);
/**
* Returns {@code true} if this queue contains the specified element.
* More formally, returns {@code true} if and only if this queue contains
* at least one element {@code e} such that {@code o.equals(e)}.
*
* 判断队列是否存在给定的元素。如果存在返回 true,如果不存在返回 false
*
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
* @throws ClassCastException if the class of the specified element
* is incompatible with this queue
* (<a href="../Collection.html#optional-restrictions">optional</a>)
* @throws NullPointerException if the specified element is null
* (<a href="../Collection.html#optional-restrictions">optional</a>)
*/
public boolean contains(Object o);
/**
* Removes all available elements from this queue and adds them
* to the given collection. This operation may be more
* efficient than repeatedly polling this queue. A failure
* encountered while attempting to add elements to
* collection {@code c} may result in elements being in neither,
* either or both collections when the associated exception is
* thrown. Attempts to drain a queue to itself result in
* {@code IllegalArgumentException}. Further, the behavior of
* this operation is undefined if the specified collection is
* modified while the operation is in progress.
*
* 将队列中的元素全部移到指定的集合中,队列本身清空成空队列。
*
* @param c the collection to transfer elements into
* @return the number of elements transferred
* @throws UnsupportedOperationException if addition of elements
* is not supported by the specified collection
* @throws ClassCastException if the class of an element of this queue
* prevents it from being added to the specified collection
* @throws NullPointerException if the specified collection is null
* @throws IllegalArgumentException if the specified collection is this
* queue, or some property of an element of this queue prevents
* it from being added to the specified collection
*/
int drainTo(Collection<? super E> c);
/**
* Removes at most the given number of available elements from
* this queue and adds them to the given collection. A failure
* encountered while attempting to add elements to
* collection {@code c} may result in elements being in neither,
* either or both collections when the associated exception is
* thrown. Attempts to drain a queue to itself result in
* {@code IllegalArgumentException}. Further, the behavior of
* this operation is undefined if the specified collection is
* modified while the operation is in progress.
*
* 和 drainTo(Collection<? super E> c)作用相同,只是增加了迁移元素个数的界定。
* 迁移后队列本身也是置为空队列。
*
* @param c the collection to transfer elements into
* @param maxElements the maximum number of elements to transfer
* @return the number of elements transferred
* @throws UnsupportedOperationException if addition of elements
* is not supported by the specified collection
* @throws ClassCastException if the class of an element of this queue
* prevents it from being added to the specified collection
* @throws NullPointerException if the specified collection is null
* @throws IllegalArgumentException if the specified collection is this
* queue, or some property of an element of this queue prevents
* it from being added to the specified collection
*/
int drainTo(Collection<? super E> c, int maxElements);
ArrayBlockingQueue
ArrayBlockingQueue 是一个基于数组这种数据结构实现的有界的先进先出队列。即队首元素是进入队列最早的元素,队尾元素时最后进入队列的元素。
ArrayBlockingQueue 是一个典型的在生产者消费者模式中用作存储缓冲任务的有界队列,由生产者往队列中添加任务,由消费者从队列中获取任务。一旦 ArrayBlockingQueue 初始化之后,队列的长度的就固定不能更改。如果生产者往队列中添加任务时,队列已经满了,那么添加时线程会被阻塞;如果消费者从队列中获取任务时,队列已经空了,那么消费者获取任务的线程会被阻塞。
ArrayBlockingQueue 内部类 Itr 实现了 Iterator 接口,内部类 Itrs 保证在队列中的元素发生变化时,循环队列不会出错。ArrayBlockingQueue 利用 Itrs 和 Itr 来实现迭代器相关功能。
Itrs
Itrs 维护这一个 Itr 链表,用于在一个队列下的多个 Itr 迭代器中共享队列元素,保证多个迭代器中的元素数据的一致性。
虽然 Itrs 这个设计增加了维护上的复杂性,但是为了保证迭代器在删除元素时,各个迭代器中能够保持一致,这个 Itrs 的设计时有必要的。Itrs 通过
1.跟踪 takeIndex 循环到 0 的次数。提供 takeIndexWrapped 方法,当 takeIndex 循环到 0 时,清除过期迭代。
2.提供 removedAt,通知所有的迭代器执行 removedAt 来保证所有的 Itr 迭代器数据保持一致。
以上的两项操作应当能够保证 Itr 迭代器间的一致性,但是增加了许多其他的操作来维护这些 Itr 迭代器。Itrs 通过一个链表和弱引用来维护 Itr 迭代器,并通过一下三种方式清空 Itr 迭代器:
- 当创建 Itr 迭代器时,检查链表中的 Itr 迭代器是否过期。
- 当 takeIndex 循环到 0 时,检查超过一次循环,但是从未被使用的迭代器。
- 如果队列被清空,那么所有的 Itr 迭代器都会被通知数据作废。
所以为了保证正确性,removedAt、shutdown 和 takeIndexWrapped 方法都做检查 Itr 迭代器是否过期的操作。如果元素都过期,GC 如果决定迭代器作废或者迭代器通知自己过期,那么这些过期的元素会被清除。这个操作不需要做额外的其他操作就可完成。
class Itrs {
/**
* Itr 迭代器单向链表。Itr 迭代器使用的是弱引用。
*/
private class Node extends WeakReference<Itr> {
Node next;
Node(Itr iterator, Node next) {
super(iterator);
this.next = next;
}
}
// 获取元素的下标第几次到达 0 的位置
int cycles = 0;
// Itr 链表的头部元素
private Node head;
// 清理的位置
private Node sweeper = null;
// 过期探测自旋次数
private static final int SHORT_SWEEP_PROBES = 4;
private static final int LONG_SWEEP_PROBES = 16;
Itrs(Itr initial) {
register(initial);
}
/**
* 清除过期的 Itr 迭代器。只有 Itr 迭代器线程才会调用该方法
*
* @param tryHarder 是否开启 try-harder 模式。该参数决定循环次数
*/
void doSomeSweeping(boolean tryHarder) {
// 自旋次数
int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
Node o, p;
// 迭代器的过期队列
final Node sweeper = this.sweeper;
// 是否存在过期迭代器的标志。true 表示不存在,false 表示存在
boolean passedGo;
if (sweeper == null) {
o = null;
p = head;
passedGo = true;
} else {
o = sweeper;
p = o.next;
passedGo = false;
}
// 自旋检查清除过期的迭代器
for (; probes > 0; probes--) {
// 迭代器队列不存在或者过期队列不存在
if (p == null) {
// 如果 passedGo==true,表示 sweeper 队列不存在,那么跳出循环。此时,不存在过期 Itr 迭代器。
if (passedGo)
break;
//迭代器发生变化,那么检测 Itr 迭代器队列中是否存在过期的 Itr 迭代器
o = null;
p = head;
passedGo = true;
}
final Itr it = p.get();
final Node next = p.next;
// 判断迭代器是否已经过期
if (it == null || it.isDetached()) {
// 如果发现了过期的迭代器,那么自旋次数调整成 try-harder 模式,用于后续继续查找过期的 Itr 迭代器
probes = LONG_SWEEP_PROBES;
// 清空当前过期的迭代器
p.clear();
p.next = null;
// o == null 说明是从迭代器链表中查找到的过期迭代器,并且查找的是链表中的第一个节点。需要重新构建头结点的指向。
if (o == null) {
// 更新 head 并且通过自旋在链路上不断向后查找过期的迭代器
head = next;
// 如果新的头结点指向为 null,说明没有 Itr 迭代器链路,那么直接返回。
if (next == null) {
itrs = null;
return;
}
}
// 将节点 p 剔出队列,重新连接 p 的上一个节点 o 的 next 指向,指向 p.next。
else
o.next = next;
// 迭代器有效,那么更新校验节点的上一个节点的指向,即开始校验下一个节点,那么上一个节点的指向指向当前节点。
} else {
o = p;
}
// 改变 p 的指向,继续检查链路上的
p = next;
}
// 设置清理的位置
this.sweeper = (p == null) ? null : o;
}
/**
* 项 Itrs 中注册一个 Itr 迭代器
*/
void register(Itr itr) {
// 从队首入队
head = new Node(itr, head);
}
/**
* 如果 takeIndex 循环到 0,那么调用 takeIndexWrapped,删除过期的迭代器
*/
void takeIndexWrapped() {
// 循环到 0, 的次数加一
cycles++;
// 遍历迭代器队列,检查过期迭代器,并将过期迭代器删除。
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
final Node next = p.next;
// 遍历 Itr 迭代器链表,利用 Itr 迭代器的 takeIndexWrapped 判断迭代器是否过期
if (it == null || it.takeIndexWrapped()) {
//
p.clear();
p.next = null;
if (o == null)
head = next;
else
o.next = next;
} else {
o = p;
}
p = next;
}
if (head == null) // no more iterators to track
itrs = null;
}
/**
* 如果阻塞队列的节点被移除时,通知 Itrs 迭代器检查并删除所有过期 Itr 迭代器
*/
void removedAt(int removedIndex) {
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
final Node next = p.next;
if (it == null || it.removedAt(removedIndex)) {
// 将引用置空,让 GC 回收
p.clear();
// 将节点的下一个节点的指向置空
p.next = null;
//重新构建链路关系,即当前的节点踢出链路
if (o == null)
head = next;
else
o.next = next;
} else {
o = p;
}
p = next;
}
if (head == null) // no more iterators to track
itrs = null;
}
/**
* 通知所有的迭代器队列被清空了
*/
void queueIsEmpty() {
// 遍历 Itr 迭代器链路,清空所有的迭代器
for (Node p = head; p != null; p = p.next) {
Itr it = p.get();
if (it != null) {
p.clear();
it.shutdown();
}
}
head = null;
itrs = null;
}
/**
* 元素出队列时同步更新 Itr 迭代器
*/
void elementDequeued() {
// assert lock.getHoldCount() == 1;
if (count == 0)
queueIsEmpty();
else if (takeIndex == 0)
takeIndexWrapped();
}
}
Itr
Itr 是 ArrayBlockingQueue 的迭代器实现类。ArrayBlockingQueue 本身继承 Iterator 接口,内部则利用内部类 Itr 实现迭代器相关功能。当外部需要一个迭代器时,ArrayBlockingQueue 创建一个 Itr 对象提供迭代器相关功能。
外部获取 ArrayBlockingQueue 的迭代器时(即 Itr 在初始化过程)会获取到当前 ArrayBlockingQueue 的部分数据,包括当前游标位置,游标指向的元素等。如果队列本身数据发生变化,比如已经是个空队列了,迭代器获取到的当前数据比如游标位置和指向的元素不会丢失,即尽管 ArrayBlockingQueue 的 size 已经为 0,但是迭代器 hasNext 依然返回 true,并且 next 返回的值是 Itr 初始化时游标指向的元素。继续遍历时,由于 Itr 已经过期,所以返回 false。
源码学习:
private class Itr implements Iterator<E> {
// 迭代器下一个元素的下标位置。如果没有元素则为-1
private int cursor;
// 迭代器下一个元素的引用
private E nextItem;
// 迭代器下一个元素的下标位置
private int nextIndex;
// 最后一次迭代指向的元素。迭代器每次调用 next 时更新 lastRet 的值,更新成 nextIndex。lastItem 是 lastRet 指向的元素
private E lastItem;
// 最后一次迭代指向的 nextIndex。迭代器每次调用 next 时更新 lastRet 的值,更新成 nextIndex。
private int lastRet;
// 初始化时 takeIndex 的位置。如果初始化时队列是空的,那么为-3
private int prevTakeIndex;
// 初始化时循环次数
private int prevCycles;
// 状态标志 NONE 表示不可用或者未定义
private static final int NONE = -1;
// 状态标志 REMOVED 表示该位置上的元素被非本迭代器删除操作删除。
private static final int REMOVED = -2;
// prevTakeIndex 的特殊值,表示 prevTakeIndex 处于卸载的状态,即 Itrs 不在维护当前迭代器。
private static final int DETACHED = -3;
Itr() {
// assert lock.getHoldCount() == 0;
lastRet = NONE;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// count == 0 表示队列没有任务元素
if (count == 0) {
cursor = NONE;
nextIndex = NONE;
prevTakeIndex = DETACHED;
} else {
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
prevTakeIndex = takeIndex;
nextItem = itemAt(nextIndex = takeIndex);
// 游标位置未到队尾时是 takeIndex+1;如果 takeIndex 的位置是队列最后一个元素,那么 cursor 是 0;如果队列是空队列,那么 cursor 是-1
cursor = incCursor(takeIndex);
// 向 Itrs 注册当前迭代器
if (itrs == null) {
itrs = new Itrs(this);
} else {
itrs.register(this); // in this order
itrs.doSomeSweeping(false);
}
prevCycles = itrs.cycles;
}
} finally {
lock.unlock();
}
}
/**
* 当前迭代器是否被卸载。
* 如果当前迭代器被卸载,那么 prevTakeIndex 会被置为 DETACHED(-3)。
* 所以判断是否被卸载直接通过 prevTakeIndex<0 来判断
*/
boolean isDetached() {
return prevTakeIndex < 0;
}
/**
* 计算游标的位置
* 在没有到达队尾时,takeIndex + 1;takeIndex 到达队尾后则是 0;如果队列是空队列则返回-1
*/
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
if (++index == items.length)
index = 0;
if (index == putIndex)
index = NONE;
return index;
}
/**
* 判断给定的位置是否已经过期。
* index 表示给第的位置
* prevTakeIndex takeIndex 在移动前的位置
* dequeues 表示出队列的数量
* length 表示队列长度
* 过期的条件:1. 给第位置必须是大于 0 并且 2 出队数量 dequeues 大于给第位置和上一个获取元素的位置的距离
*/
private boolean invalidated(int index, int prevTakeIndex,
long dequeues, int length) {
if (index < 0)
return false;
int distance = index - prevTakeIndex;
if (distance < 0)
distance += length;
return dequeues > distance;
}
/**
* 如果有必要则重新更新 lastRet、nextIndex、cursor、prevTakeIndex、prevCycles 等迭代器重要属性的值。
* 迭代器在三种情况下会调用该方法
* 1. 调用 hasNext 方法但是已经没有下一个元素并且该迭代器没有被卸载时
* 2. 调用 next 方法并且迭代器没有卸载时
* 3. 调用 remove 元素并且迭代器没有被卸载时
*/
private void incorporateDequeues() {
final int cycles = itrs.cycles;
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
final int prevCycles = this.prevCycles;
final int prevTakeIndex = this.prevTakeIndex;
/**
* 如果 takeIndex 发生变化则做检查
* cycles != prevCycles 循环次数发生变化,那么 takeIndex 一定发生变化
*/
if (cycles != prevCycles || takeIndex != prevTakeIndex) {
final int len = items.length;
// 计算 takeIndex 的移动距离。
long dequeues = (cycles - prevCycles) * len
+ (takeIndex - prevTakeIndex);
if (invalidated(lastRet, prevTakeIndex, dequeues, len))
lastRet = REMOVED;
if (invalidated(nextIndex, prevTakeIndex, dequeues, len))
nextIndex = REMOVED;
if (invalidated(cursor, prevTakeIndex, dequeues, len))
cursor = takeIndex;
// 如果 cursor、nextIndex、lastRet 都是无效那么说明元素在发生变化,Itrs 没有通知到 Itr 做同步更新,直接将当前的 Itr 设置成卸载状态。
if (cursor < 0 && nextIndex < 0 && lastRet < 0)
detach();
else {
this.prevCycles = cycles;
this.prevTakeIndex = takeIndex;
}
}
}
/**
* 如果 Itrs 不需要再维护当前的迭代器,那么将当前迭代职位卸载。即 Itrs 不再通知当前迭代器元素变化情况。
*/
private void detach() {
// Switch to detached mode
// assert lock.getHoldCount() == 1;
// assert cursor == NONE;
// assert nextIndex < 0;
// assert lastRet < 0 || nextItem == null;
// assert lastRet < 0 ^ lastItem != null;
if (prevTakeIndex >= 0) {
// assert itrs != null;
prevTakeIndex = DETACHED;
// try to unlink from itrs (but not too hard)
itrs.doSomeSweeping(true);
}
}
/**
* 判断是否有下一个元素。
* 由于考虑到性能问题,hasNext 直接通过属性 nextItem 是否有值来判断。所以如果队列已经发生变化,比如队列已经是空队列了,
* 但是 hasNext 依然会返回 true。
*/
public boolean hasNext() {
// assert lock.getHoldCount() == 0;
if (nextItem != null)
return true;
noNext();
return false;
}
/**
* 当调用 hasNext 发现没有以下一个元素时,如果迭代器不是卸载状态,那么检查是否需要更新重要属性是否过期,并且将迭代器置为卸载模式
*/
private void noNext() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// assert cursor == NONE;
// assert nextIndex == NONE;
if (!isDetached()) {
// assert lastRet >= 0;
incorporateDequeues(); // might update lastRet
if (lastRet >= 0) {
lastItem = itemAt(lastRet);
// assert lastItem != null;
detach();
}
}
// assert isDetached();
// assert lastRet < 0 ^ lastItem != null;
} finally {
lock.unlock();
}
}
/**
* 返回下一个元素
*
*/
public E next() {
// assert lock.getHoldCount() == 0;
// nextItem 属性指向的是下一个元素。
final E x = nextItem;
if (x == null)
throw new NoSuchElementException();
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (!isDetached())
incorporateDequeues();
// 维护 lastRet 属性
lastRet = nextIndex;
final int cursor = this.cursor;
/*
* 维护 nextItem、nextIndex 和 cursor 属性
* cursor 有效(cursor >= 0)
* nextItem 为当前游标 cursor 指向的元素。
* nextIndex 为当前游标 cursor 的值。
* cursor 在原来基础上+1。如果已经到队尾,那么 cursor 为 0
*/
if (cursor >= 0) {
nextItem = itemAt(nextIndex = cursor);
// assert nextItem != null;
this.cursor = incCursor(cursor);
} else {
nextIndex = NONE;
nextItem = null;
}
} finally {
lock.unlock();
}
return x;
}
/**
* 迭代器删除元素
* 1.通过 Itrs 通知所有的迭代器删除元素;调用 ArrayBlockingQueue 的 removeAt 方法删除队列元素。
*/
public void remove() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// 如果迭代器不是卸载模式,那么更新迭代器的重要属性。这里可能会更新最后出队列的位置属性(lastRet)或者迭代器被卸载
if (!isDetached())
incorporateDequeues();
final int lastRet = this.lastRet;
this.lastRet = NONE;
// lastRet >= 0 表示 lastRet 属性有效
if (lastRet >= 0) {
// 如果迭代器没有被卸载,那么通过调用 ArrayBlockingQueueu 的 removeAt 删除队列元素
if (!isDetached())
removeAt(lastRet);
// 迭代器已经被卸载,如果 lastItem 和 lastRet 位置指向的元素一样(队列上的该元素未发生变化),那么通过调用 removeAt 删除队列元素,否则不做处理
else {
final E lastItem = this.lastItem;
// assert lastItem != null;
this.lastItem = null;
if (itemAt(lastRet) == lastItem)
removeAt(lastRet);
}
} else if (lastRet == NONE)
throw new IllegalStateException();
// 游标和下一个元素位置已经无效那么卸载当前迭代器。
if (cursor < 0 && nextIndex < 0)
detach();
} finally {
lock.unlock();
// assert lastRet == NONE;
// assert lastItem == null;
}
}
/**
* 关闭迭代器。将属性置为无效状态
* 该方法一般在队列为空或者迭代器已经完全过时的情况下会通知迭代器关闭
*/
void shutdown() {
// assert lock.getHoldCount() == 1;
cursor = NONE;
if (nextIndex >= 0)
nextIndex = REMOVED;
if (lastRet >= 0) {
lastRet = REMOVED;
lastItem = null;
}
prevTakeIndex = DETACHED;
// Don't set nextItem to null because we must continue to be
// able to return it on next().
//
// Caller will unlink from itrs when convenient.
}
/**
* 计算给定位置和 prevTakeIndex 的距离
* length 表示队列的长度
*/
private int distance(int index, int prevTakeIndex, int length) {
int distance = index - prevTakeIndex;
if (distance < 0)
distance += length;
return distance;
}
/**
* 迭代器删除给定位置上的元素
* 该方法不会改变 ArrayBlockingQueueu 底层数组 Items[]Object[] items,只是通过操作重新维护重要属性的值。
* 如果调整后的属性值是过期的状态,那么将当前迭代器卸载。
* 如果迭代器被卸载,那么返回 true,否则返回 false。
*
* @return true if this iterator should be unlinked from itrs
*/
boolean removedAt(int removedIndex) {
// assert lock.getHoldCount() == 1;
if (isDetached())
return true;
final int cycles = itrs.cycles;
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
final int prevCycles = this.prevCycles;
final int prevTakeIndex = this.prevTakeIndex;
final int len = items.length;
int cycleDiff = cycles - prevCycles;
if (removedIndex < takeIndex)
cycleDiff++;
final int removedDistance =
(cycleDiff * len) + (removedIndex - prevTakeIndex);
// assert removedDistance >= 0;
int cursor = this.cursor;
if (cursor >= 0) {
int x = distance(cursor, prevTakeIndex, len);
if (x == removedDistance) {
if (cursor == putIndex)
this.cursor = cursor = NONE;
}
else if (x > removedDistance) {
// assert cursor != prevTakeIndex;
this.cursor = cursor = dec(cursor);
}
}
int lastRet = this.lastRet;
if (lastRet >= 0) {
int x = distance(lastRet, prevTakeIndex, len);
if (x == removedDistance)
this.lastRet = lastRet = REMOVED;
else if (x > removedDistance)
this.lastRet = lastRet = dec(lastRet);
}
int nextIndex = this.nextIndex;
if (nextIndex >= 0) {
int x = distance(nextIndex, prevTakeIndex, len);
if (x == removedDistance)
this.nextIndex = nextIndex = REMOVED;
else if (x > removedDistance)
this.nextIndex = nextIndex = dec(nextIndex);
}
else if (cursor < 0 && nextIndex < 0 && lastRet < 0) {
this.prevTakeIndex = DETACHED;
return true;
}
return false;
}
/**
* takeIndex 重新回到 0 的位置,检查迭代器是否过期。
*
* @return true 表示迭代器应该被卸载,false 表示迭代器依然有效。
*/
boolean takeIndexWrapped() {
// assert lock.getHoldCount() == 1;
if (isDetached())
return true;
if (itrs.cycles - prevCycles > 1) {
// All the elements that existed at the time of the last
// operation are gone, so abandon further iteration.
shutdown();
return true;
}
return false;
}
ArrayBlockingQueue
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
// 底层存储具体数据的数组。ArrayBlockingQueue 没有使用任何数组拷贝等技术,所以一旦初始化后,队列的最大长度就固定了
final Object[] items;
// 获取数据的下标。items 是被循环利用的,所以下标 0 的位置不是队列的头部,takeIndex 才是。
int takeIndex;
// 存数据的下标位置。items 是被循环利用的,所以下标 0 的位置不是队列的尾部,putIndex 才是。
int putIndex;
// 队列中有数据的数量
int count;
// 重入锁,用于保证并发操作队列的线程安全。
final ReentrantLock lock;
// 竞态条件。如果线程获取数据时但是队列没有任务数据,那么线程将会通过调用 notEmpty.await()阻塞等待,知道直到其他线程往队列中添加元素时调用 notEmpty.signal 通知到当前线程时,线程继续执行。
private final Condition notEmpty;
// 竞态条件。如果线程存储数据时但是队列已满,无法寄出添加元素,那么线程将会通过调用 notFull.await()阻塞等待,知道直到其他线程从队列中获取元素时调用 notFull.signal 通知到当前线程时,线程继续执行。
private final Condition notFull;
/**
* 迭代器维护器
*/
transient Itrs itrs = null;
// Internal helper methods
/**
* 计算游标的位置。
* 给定值 i 是当前游标。使用场景是如果遇到删除元素时,游标需要重新计算,做扣减一的操作。
*/
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
/**
* 返回给定下标位置上的数组元素。
*/
@SuppressWarnings("unchecked")
final E itemAt(int i) {
return (E) items[i];
}
/**
* 校验是否是空对象。如果是空对象则抛出 NullPointerException 异常
*
* @param v the element
*/
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
/**
* 元素入队
* 入队操作前后需要上锁和释放锁以保证线程安全
*/
private void enqueue(E x) {
final Object[] items = this.items;
// 将元素放到 putIndex 下标位置
items[putIndex] = x;
// putIndex 后移一位
if (++putIndex == items.length)
putIndex = 0;
// 有效元素个数统计加一
count++;
// 发送不是空队列信号。如果有线程在获取时遇到空队列进度到阻塞,那么此时将唤醒阻塞队列的第一个节点。
notEmpty.signal();
}
/**
* 元素出队
* 出队需要在操作前和操作后加上上锁和释放锁的操作
*/
private E dequeue() {
final Object[] items = this.items;
@SuppressWarnings("unchecked")
// 获取到 takeIndex 元素。该元素就是需要出队的元素
E x = (E) items[takeIndex];
// 将 takeIndex 位置置为 null
items[takeIndex] = null;
// takeIndex 后移一位。如果已经是队尾则置为 0
if (++takeIndex == items.length)
takeIndex = 0;
// 队列有效元素个数减一
count--;
// 通知 Itrs 迭代管理器元素出队
if (itrs != null)
itrs.elementDequeued();
// 发布队列元素未满信号。如果有线程正在做入队操作,但是受阻于队列已满,那么会进度等待队列。该信号将唤醒该等待队列的第一个节点。
notFull.signal();
return x;
}
/**
* 根据给出的下标删除元素
* 该方法需要加锁后操作,保证线程安全。
*/
void removeAt(final int removeIndex) {
final Object[] items = this.items;
// 如果给定的下标和 takeIndex 一致,那么执行和 dequeue 一样的逻辑
if (removeIndex == takeIndex) {
// removing front item; just advance
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
// 获取到 putIndex 的位置。putIndex 是元素位移的结束位置(putIndex 的位置和后续知道 takeIndex 之间的元素为 null,不需要做处理)。
final int putIndex = this.putIndex;
for (int i = removeIndex;;) {
int next = i + 1;
// 如果 next 是队列的长度,那么置为 0
if (next == items.length)
next = 0;
// next != putIndex 说明还是有效的元素。由于是数组删除元素,所以在有效的区间内元素往前移动一位。
if (next != putIndex) {
// 将后续的元素覆盖当前元素
items[i] = items[next];
// 标志位+1。
i = next;
// 已经操作到 putIndex,跳出循环。
} else {
items[i] = null;
this.putIndex = i;
break;
}
}
// 队列有效元素减一
count--;
// 通知 Itrs 迭代管理器删除指定位置的元素。主要是同步 Itr 迭代器的重要属性。
if (itrs != null)
itrs.removedAt(removeIndex);
}
// 发布队列元素未满信号。
notFull.signal();
}
/**
* 构造函数,初始化同步队列
*
* @param capacity the capacity of this queue
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
/**
* 构造函数,初始化同步队列
*
* @param capacity the capacity of this queue
* @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order;
* if {@code false} the access order is unspecified.
* @throws IllegalArgumentException if {@code capacity < 1}
*/
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
// 初始化 capacity 大小的数组
this.items = new Object[capacity];
// 构造可重入锁。队列中的很多方法都需要通过锁保证线程同步。
lock = new ReentrantLock(fair);
// 竞态条件。用于如果队列为空时,为获取元素的线程提供等待队列;元素入队时通知该等待队列。
notEmpty = lock.newCondition();
// 竞态条件。用于队列如果已经达到容量上限时为添加元素的线程提供等待队列;元素被操作出队时,通知该等待队列。
notFull = lock.newCondition();
}
/**
* 构造函数,初始化同步队列
*
* @param capacity the capacity of this queue
* @param fair if {@code true} then queue accesses for threads blocked
* on insertion or removal, are processed in FIFO order;
* if {@code false} the access order is unspecified.
* @param c the collection of elements to initially contain
* @throws IllegalArgumentException if {@code capacity} is less than
* {@code c.size()}, or less than 1.
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
public ArrayBlockingQueue(int capacity, boolean fair,
Collection<? extends E> c) {
this(capacity, fair);
final ReentrantLock lock = this.lock;
lock.lock(); // Lock only for visibility, not mutual exclusion
try {
int i = 0;
try {
for (E e : c) {
checkNotNull(e);
items[i++] = e;
}
} catch (ArrayIndexOutOfBoundsException ex) {
throw new IllegalArgumentException();
}
count = i;
putIndex = (i == capacity) ? 0 : i;
} finally {
lock.unlock();
}
}
/**
* 往队列中添加元素。
* 底层通过 offer 实现。
* 如果队列已经满了,添加元素的线程不会阻塞,而是会收到 IllegalStateException 异常。
* 如果添加的是 null,抛出 NullPointerException
*
* @param e the element to add
* @return {@code true} (as specified by {@link Collection#add})
* @throws IllegalStateException if this queue is full
* @throws NullPointerException if the specified element is null
*/
public boolean add(E e) {
return super.add(e);
}
/**
* 往队列中添加元素。
* 如果元素是 null,则抛出 NullPointerException。
* 如果队列已经满了,线程不会阻塞而是返回 false
* 如果添加成功返回 true,否则返回 false
*
* @throws NullPointerException if the specified element is null
*/
public boolean offer(E e) {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count == items.length)
return false;
else {
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
/**
* 往队列中添加元素。
* 如果元素是 null 则抛出 NullPointerException
* 如果队列已经满了,线程阻塞等待队列允许添加元素。
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public void put(E e) throws InterruptedException {
// 校验元素是否是 null,如果是则抛出 NullPointerException
checkNotNull(e);
final ReentrantLock lock = this.lock;
// 添加可以响应线程中断的锁。即如果在 lock.lockInterruptibly()时线程被阻塞时线程被中断,那么抛出 InterruptedException 异常
lock.lockInterruptibly();
try {
// 如果队列已经满了,那么线程进入到 notFull 直到 notFull 调用 notFull.signal()通知可以继续添加。
while (count == items.length)
notFull.await();
// 说明对了可以继续添加元素。使用 enqueue 方法入队
enqueue(e);
} finally {
lock.unlock();
}
}
/**
* 往队列中添加元素。
* 如果元素是 null 则抛出 NullPointerException
* 如果队列已经满了,线程阻塞等待队列允许添加元素。
* 支持设置等待往队列中添加元素的超时时间。
* 如果等待超时则抛出 InterruptedException
*
* @throws InterruptedException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
checkNotNull(e);
long nanos = unit.toNanos(timeout);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == items.length) {
if (nanos <= 0)
return false;
// 设置等待的超时时间
nanos = notFull.awaitNanos(nanos);
}
enqueue(e);
return true;
} finally {
lock.unlock();
}
}
/**
* 获取元素
* 如果队列是空队列,那么返回 Null
* 该方法不会阻塞线程
*/
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
/**
* 获取元素
* 如果队列是空队列,那么线程阻塞直到 notEmpty.signal 通知到等待队列中的节点。
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
// 添加支持线程中断的锁
lock.lockInterruptibly();
try {
// 如果队列是空队列,那么线程阻塞
while (count == 0)
notEmpty.await();
// 线程不是空队列,那么队首元素出队
return dequeue();
} finally {
lock.unlock();
}
}
/**
* 获取元素
* 如果队列是空队列,那么线程阻塞直到 notEmpty.signal 通知到等待队列中的节点。
* 支持设置队列为空是线程等待的超时时间。
*/
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;
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
/**
* 获取队首元素。
* 操作线程不会阻塞
* 如果队列是空队列,那么返回 null
*/
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
// this doc comment is overridden to remove the reference to collections
// greater in size than Integer.MAX_VALUE
/**
* 返回队列有效元素的个数
*
* @return the number of elements in this queue
*/
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
// this doc comment is a modified copy of the inherited doc comment,
// without the reference to unlimited queues.
/**
* 返回队列允许添加元素的数量。
*/
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}
/**
* 删除元素
* 比较队列中的元素和指定元素是否相同,如果相同则调用 removeAt 方法删除元素。
* 如果删除成功则返回 true,否则返回 false。
*
* @param o element to be removed from this queue, if present
* @return {@code true} if this queue changed as a result of the call
*/
public boolean remove(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i])) {
removeAt(i);
return true;
}
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
/**
* 判断队列是否包含指定的元素
* 如果包含则返回 true,否则返回 false。
*
* @param o object to be checked for containment in this queue
* @return {@code true} if this queue contains the specified element
*/
public boolean contains(Object o) {
if (o == null) return false;
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
if (count > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
if (o.equals(items[i]))
return true;
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
return false;
} finally {
lock.unlock();
}
}
/**
* 将队列中的元素转成一个新的数组返回。
*
* @return an array containing all of the elements in this queue
*/
public Object[] toArray() {
Object[] a;
final ReentrantLock lock = this.lock;
lock.lock();
try {
final int count = this.count;
a = new Object[count];
int n = items.length - takeIndex;
// count <= n 说明 putIndex>= takeIndex 并且(putIndex< iTems.length 或者 putIndex = 0),如此直接否则 takeIndex 后续的元素即可
if (count <= n)
System.arraycopy(items, takeIndex, a, 0, count);
// 否则就需要否则赋值 takeIndex 到 Items.length 之间的元素和 0 到 putIndex 之间的元素
else {
System.arraycopy(items, takeIndex, a, 0, n);
System.arraycopy(items, 0, a, n, count - n);
}
} finally {
lock.unlock();
}
return a;
}
/**
* 将队列清空
*/
public void clear() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock();
try {
int k = count;
if (k > 0) {
final int putIndex = this.putIndex;
int i = takeIndex;
do {
items[i] = null;
if (++i == items.length)
i = 0;
} while (i != putIndex);
takeIndex = putIndex;
count = 0;
if (itrs != null)
itrs.queueIsEmpty();
for (; k > 0 && lock.hasWaiters(notFull); k--)
notFull.signal();
}
} finally {
lock.unlock();
}
}
/**
* 清空队列并将队列中的元素添加到集合中
*
* @throws UnsupportedOperationException {@inheritDoc}
* @throws ClassCastException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @throws IllegalArgumentException {@inheritDoc}
*/
public int drainTo(Collection<? super E> c, int maxElements) {
checkNotNull(c);
if (c == this)
throw new IllegalArgumentException();
if (maxElements <= 0)
return 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 {
// Restore invariants even if c.add() threw
if (i > 0) {
count -= i;
takeIndex = take;
if (itrs != null) {
if (count == 0)
itrs.queueIsEmpty();
else if (i > take)
itrs.takeIndexWrapped();
}
for (; i > 0 && lock.hasWaiters(notFull); i--)
notFull.signal();
}
}
} finally {
lock.unlock();
}
}
}