1、简介
一个由数组支持的有界阻塞队列。它的本质是一个基于数组的BlockingQueue的实现。
它的容纳大小是固定的。此队列按 FIFO(先进先出)原则对元素进行排序。
队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。
新元素插入到队列的尾部,队列检索操作则是从队列头部开始获得元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。
一旦创建了这样的缓存区,就不能再增加其容量。
试图向已满队列中放入元素会导致放入操作受阻塞,直到BlockingQueue里有新的唤空间才会被醒继续操作;
试图从空队列中检索元素将导致类似阻塞,直到BlocingkQueue进了新货才会被唤醒。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。
默认情况下,不保证是这种排序。然而,通过在构造函数将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。
公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
此类及其迭代器实现了 Collection 和 Iterator 接口的所有可选 方法。
注意1:它是有界阻塞队列。它是数组实现的,是一个典型的“有界缓存区”。数组大小在构造函数指定,而且从此以后不可改变。
注意2:是它线程安全的,是阻塞的,具体参考BlockingQueue的“注意4”。
注意3:不接受 null 元素
注意4:公平性 (fairness)可以在构造函数中指定。
2、成员变量及构造方法
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable {
// 序列化参数
private static final long serialVersionUID = -817911632652898426L;
// 真正存入数据的数组
final Object[] items;
// take, poll, peek or remove的下一个索引
int takeIndex;
// put, offer, or add的下一个索引
int putIndex;
// 队列中元素个数
int count;
// 可重入锁
final ReentrantLock lock;
// 队列不为空的条件
private final Condition notEmpty;
// 队列未满的条件
private final Condition notFull;
// 当前活动迭代器的共享状态,如果已知不存在,则为空。允许队列操作更新迭代器状态
transient Itrs itrs = null;
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
public ArrayBlockingQueue(int capacity, boolean fair) {
if (capacity <= 0)
throw new IllegalArgumentException();
this.items = new Object[capacity]; // 创建一个数组
lock = new ReentrantLock(fair); // 创建一个锁
notEmpty = lock.newCondition(); // 在锁上创建条件变量
notFull = lock.newCondition();
}
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
this(capacity, fair); //调用上面的构造方法
// 将集合c种的元素一个个放入 队列中
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();
}
}
}
成员变量:主要是 Object[] items数组 takeIndex putIndex ReentrantLock notEmpty notFull
构造方法:就是创建一个数组,ReentrantLock,在锁上创建两个条件变量,如果参数有集合,就将集合中元素放入队列
3、方法介绍
应重点关注 入队|出队的方法,特别是 put() 和 take()阻塞方法的实现。
3.1、增加元素
enqueue(E x)
// 元素放入队列,注意调用这个方法时都要先加锁
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();
}
add(E e)
// 添加一个元素,其实super.add里面调用了offer方法
public boolean add(E e) {
return super.add(e);
}
offer(E e)
offer(E e, long timeout, TimeUnit unit)
// 加入成功返回true,否则返回false
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();
}
}
// 带有超时时间的插入方法,unit表示是按秒、分、时哪一种
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; //超时,则返回false
nanos = notFull.awaitNanos(nanos); // 带有超时等待的阻塞方法
}
enqueue(e); //入队
return true;
} finally {
lock.unlock();
}
}
put(E e)
// 如果队列已满的话,就会等待
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly(); //和lock()方法的区别是让它在阻塞时也可抛出异常跳出
try {
while (count == items.length)
notFull.await(); //这里就是阻塞了,要注意。如果运行到这里,那么它会释放上面的锁,一直等到notify
enqueue(e); //入队
} finally {
lock.unlock();
}
}
3.2、删除元素
dequeue()
// 元素出队,注意调用这个方法时都要先加锁
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;
}
removeAt(final int removeIndex)
// 指定删除索引上的元素
void removeAt(final int removeIndex) {
// assert lock.getHoldCount() == 1;
// assert items[removeIndex] != null;
// assert removeIndex >= 0 && removeIndex < items.length;
final Object[] items = this.items;
// 情况1:如果要删除元素正好在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 { //情况2:要删除元素不再takeIndex处
// 内部移除
final int putIndex = this.putIndex;
// 将removeIndex到putIndex中间的元素,循环移除
for (int i = removeIndex;;) {
int next = i + 1;
// 循环
if (next == items.length)
next = 0;
if (next != putIndex) {
items[i] = items[next];
i = next;
} else { //next==putIndex
items[i] = null; //因为items[putIndex]==null
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}
poll()
poll(long timeout, TimeUnit unit)
// 实现的方法,如果当前队列为空,返回null
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return (count == 0) ? null : dequeue(); //出队
} finally {
lock.unlock();
}
}
// 带有超时时间的取元素方法,否则返回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; // 超时,则返回false
nanos = notEmpty.awaitNanos(nanos); //超时等待
}
return dequeue(); // 出队
} finally {
lock.unlock();
}
}
take()
// 实现的方法,如果当前队列为空,一直阻塞
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
while (count == 0)
notEmpty.await(); // 非空跳进
return dequeue(); // 出队
} finally {
lock.unlock();
}
}
remove(Object o)
// 从队列中删除一个元素的方法。删除成功返回true,否则返回false
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();
}
}
clear()
// 清空
public void clear() {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); /加锁
try {
int k = count;
if (k > 0) {
// 从takeIndex到putIndex-1位置的元素全部置为null
final int putIndex = this.putIndex;
int i = takeIndex;
do {
items[i] = null; //将每个位置置为null
// 循环数组
if (++i == items.length)
i = 0;
} while (i != putIndex);
// 重置takeIndex指针 和 count
takeIndex = putIndex;
count = 0;
if (itrs != null)
itrs.queueIsEmpty();
// 将等待队列中的notFull上的节点全部唤醒
for (; k > 0 && lock.hasWaiters(notFull); k--)
notFull.signal();
}
} finally {
lock.unlock(); //释放锁
}
}
3.3、访问元素
peek()
// 只是看一个队列最前面的元素,取出是不删除队列中的原来元素。队列为空时返回null
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return itemAt(takeIndex); // 队列为空时返回null
} finally {
lock.unlock();
}
}
itemAt(int i)
// 返回对应索引上的元素
@SuppressWarnings("unchecked")
final E itemAt(int i) {
return (E) items[i];
}
3.4、查询操作
checkNotNull(Object v)
// 非空检查
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
size()
// 返回队列当前元素个数
public int size() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return count;
} finally {
lock.unlock();
}
}
可否改进一下:将count用volatile修饰,这样就不用size()加锁 了?
remainingCapacity()
// 返回当前队列再放入多少个元素就满队
public int remainingCapacity() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
return items.length - count;
} finally {
lock.unlock();
}
}
contains(Object o)
// 是否包含一个元素
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();
}
}
3.5、将queue中数据批量输出到其他数据结构中
toArray()
toArray(T[] a)
// 将Queue中的元素 复制到一个数组,并输出;用System.arraycopy实现
public Object[] toArray() {
Object[] a;
final ReentrantLock lock = this.lock;
lock.lock(); // 加锁
try {
final int count = this.count; //count是当前队列中的元素个数
// 创建一个大小相同的数组
a = new Object[count];
int n = items.length - takeIndex; // takeIndex到原始数组末尾的长度
// 情况1:数据范围为takeIndex-items.length-1之前的一个位置,则赋值count长度的数据
if (count <= n)
System.arraycopy(items, takeIndex, a, 0, count);
// 情况2:数据范围为takeIndex-items.length-1和0-x,则赋值这两段
else {
System.arraycopy(items, takeIndex, a, 0, n);
System.arraycopy(items, 0, a, n, count - n);
}
} finally {
lock.unlock();
}
return a;
}
// 将queue的数据复制到一个给定类型的数组
@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
final Object[] items = this.items;
final ReentrantLock lock = this.lock;
lock.lock(); //加锁
try {
final int count = this.count;
final int len = a.length;
// 利用反射创建给定类型的数组
if (len < count)
a = (T[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), count);
int n = items.length - takeIndex;
if (count <= n)
System.arraycopy(items, takeIndex, a, 0, count);
else {
System.arraycopy(items, takeIndex, a, 0, n);
System.arraycopy(items, 0, a, n, count - n);
}
if (len > count)
a[count] = null;
} finally {
lock.unlock();
}
return a;
}
drainTo(Collection<? super E> c)
drainTo(Collection<? super E> c, int maxElements)
// 取出所有元素到集合
public int drainTo(Collection<? super E> c) {
return drainTo(c, Integer.MAX_VALUE);
}
// 将queue中最多maxElements个元素,迁移到集合c中
// 注意:是迁移
public int drainTo(Collection<? super E> c, int maxElements) {
checkNotNull(c); //非空检查
// 如果c就是本queue,则抛出异常
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 {
// 将queue中的n个元素一次取出放入到c中
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 {
// 发生异常时,维护queue的不变性(就是count和takeIndex对得上)
if (i > 0) {
count -= i; // 计算还剩多少个元素没有转移
takeIndex = take; //更新takeIndex
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(); // 释放锁
}
3.6、其他方法
dec(int i)
iterator()
// 当前元素个数-1
final int dec(int i) {
return ((i == 0) ? items.length : i) - 1;
}
// 以正确的顺序返回此队列中元素的迭代器。元素将按从第一个(头)到最后一个(尾)的顺序返回
public Iterator<E> iterator() {
return new Itr(); // 内部类,此类继承了Iterator
}
// 打印输出queue信息
public String toString() {
final ReentrantLock lock = this.lock;
lock.lock(); //加锁
try {
int k = count;
if (k == 0)
return "[]";
final Object[] items = this.items;
StringBuilder sb = new StringBuilder();
sb.append('[');
for (int i = takeIndex; ; ) {
Object e = items[i];
sb.append(e == this ? "(this Collection)" : e);
if (--k == 0)
return sb.append(']').toString();
sb.append(',').append(' ');
if (++i == items.length)
i = 0;
}
} finally {
lock.unlock();
}
}
5、内部类(暂时先不做了解)
5.1、Itr 类
private class Itr implements Iterator<E> {
/** Index to look for new nextItem; NONE at end */
private int cursor;
/** Element to be returned by next call to next(); null if none */
private E nextItem;
/** Index of nextItem; NONE if none, REMOVED if removed elsewhere */
private int nextIndex;
/** Last element returned; null if none or not detached. */
private E lastItem;
/** Index of lastItem, NONE if none, REMOVED if removed elsewhere */
private int lastRet;
/** Previous value of takeIndex, or DETACHED when detached */
private int prevTakeIndex;
/** Previous value of iters.cycles */
private int prevCycles;
/** Special index value indicating "not available" or "undefined" */
private static final int NONE = -1;
/**
* Special index value indicating "removed elsewhere", that is,
* removed by some operation other than a call to this.remove().
*/
private static final int REMOVED = -2;
/** Special value for prevTakeIndex indicating "detached mode" */
private static final int DETACHED = -3;
Itr() {
// assert lock.getHoldCount() == 0;
lastRet = NONE;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (count == 0) {
// assert itrs == null;
cursor = NONE;
nextIndex = NONE;
prevTakeIndex = DETACHED;
} else {
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
prevTakeIndex = takeIndex;
nextItem = itemAt(nextIndex = takeIndex);
cursor = incCursor(takeIndex);
if (itrs == null) {
itrs = new Itrs(this);
} else {
itrs.register(this); // in this order
itrs.doSomeSweeping(false);
}
prevCycles = itrs.cycles;
// assert takeIndex >= 0;
// assert prevTakeIndex == takeIndex;
// assert nextIndex >= 0;
// assert nextItem != null;
}
} finally {
lock.unlock();
}
}
boolean isDetached() {
// assert lock.getHoldCount() == 1;
return prevTakeIndex < 0;
}
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
if (++index == items.length)
index = 0;
if (index == putIndex)
index = NONE;
return index;
}
/**
* Returns true if index is invalidated by the given number of
* dequeues, starting from prevTakeIndex.
*/
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;
}
/**
* Adjusts indices to incorporate all dequeues since the last
* operation on this iterator. Call only from iterating thread.
*/
private void incorporateDequeues() {
// assert lock.getHoldCount() == 1;
// assert itrs != null;
// assert !isDetached();
// assert count > 0;
final int cycles = itrs.cycles;
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
final int prevCycles = this.prevCycles;
final int prevTakeIndex = this.prevTakeIndex;
if (cycles != prevCycles || takeIndex != prevTakeIndex) {
final int len = items.length;
// how far takeIndex has advanced since the previous
// operation of this iterator
long dequeues = (cycles - prevCycles) * len + (takeIndex - prevTakeIndex);
// Check indices for invalidation
if (invalidated(lastRet, prevTakeIndex, dequeues, len))
lastRet = REMOVED;
if (invalidated(nextIndex, prevTakeIndex, dequeues, len))
nextIndex = REMOVED;
if (invalidated(cursor, prevTakeIndex, dequeues, len))
cursor = takeIndex;
if (cursor < 0 && nextIndex < 0 && lastRet < 0)
detach();
else {
this.prevCycles = cycles;
this.prevTakeIndex = takeIndex;
}
}
}
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);
}
}
public boolean hasNext() {
// assert lock.getHoldCount() == 0;
if (nextItem != null)
return true;
noNext();
return false;
}
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;
final E x = nextItem;
if (x == null)
throw new NoSuchElementException();
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (!isDetached())
incorporateDequeues();
// assert nextIndex != NONE;
// assert lastItem == null;
lastRet = nextIndex;
final int cursor = this.cursor;
if (cursor >= 0) {
nextItem = itemAt(nextIndex = cursor);
// assert nextItem != null;
this.cursor = incCursor(cursor);
} else {
nextIndex = NONE;
nextItem = null;
}
} finally {
lock.unlock();
}
return x;
}
public void remove() {
// assert lock.getHoldCount() == 0;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (!isDetached())
incorporateDequeues(); // might update lastRet or detach
final int lastRet = this.lastRet;
this.lastRet = NONE;
if (lastRet >= 0) {
if (!isDetached())
removeAt(lastRet);
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();
// else lastRet == REMOVED and the last returned element was
// previously asynchronously removed via an operation other
// than this.remove(), so nothing to do.
if (cursor < 0 && nextIndex < 0)
detach();
} finally {
lock.unlock();
// assert lastRet == NONE;
// assert lastItem == null;
}
}
/**
* Called to notify the iterator that the queue is empty, or that it
* has fallen hopelessly behind, so that it should abandon any
* further iteration, except possibly to return one more element
* from next(), as promised by returning true from hasNext().
*/
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.
}
private int distance(int index, int prevTakeIndex, int length) {
int distance = index - prevTakeIndex;
if (distance < 0)
distance += length;
return distance;
}
/**
* Called whenever an interior remove (not at takeIndex) occurred.
*
* @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;
}
/**
* Called whenever takeIndex wraps around to zero.
*
* @return true if this iterator should be unlinked from itrs
*/
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;
}
// /** Uncomment for debugging. */
// public String toString() {
// return ("cursor=" + cursor + " " +
// "nextIndex=" + nextIndex + " " +
// "lastRet=" + lastRet + " " +
// "nextItem=" + nextItem + " " +
// "lastItem=" + lastItem + " " +
// "prevCycles=" + prevCycles + " " +
// "prevTakeIndex=" + prevTakeIndex + " " +
// "size()=" + size() + " " +
// "remainingCapacity()=" + remainingCapacity());
// }
}
public Spliterator<E> spliterator() {
return Spliterators.spliterator
(this, Spliterator.ORDERED | Spliterator.NONNULL |
Spliterator.CONCURRENT);
}
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
// Read in items array and various fields
s.defaultReadObject();
// Check invariants over count and index fields. Note that
// if putIndex==takeIndex, count can be either 0 or items.length.
if (items.length == 0 ||
takeIndex < 0 || takeIndex >= items.length ||
putIndex < 0 || putIndex >= items.length ||
count < 0 || count > items.length ||
Math.floorMod(putIndex - takeIndex, items.length) !=
Math.floorMod(count, items.length)) {
throw new java.io.InvalidObjectException("invariants violated");
}
}
}
.5.2、Itrs 类
class Itrs {
/**
* Node in a linked list of weak iterator references.
*/
private class Node extends WeakReference<Itr> {
Node next;
Node(Itr iterator, Node next) {
super(iterator);
this.next = next;
}
}
/** Incremented whenever takeIndex wraps around to 0 */
int cycles = 0;
/** Linked list of weak iterator references */
private Node head;
/** Used to expunge stale iterators */
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);
}
void doSomeSweeping(boolean tryHarder) {
// assert lock.getHoldCount() == 1;
// assert head != null;
int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
Node o, p;
final Node sweeper = this.sweeper;
boolean passedGo; // to limit search to one full sweep
if (sweeper == null) {
o = null;
p = head;
passedGo = true;
} else {
o = sweeper;
p = o.next;
passedGo = false;
}
for (; probes > 0; probes--) {
if (p == null) {
if (passedGo)
break;
o = null;
p = head;
passedGo = true;
}
final Itr it = p.get();
final Node next = p.next;
if (it == null || it.isDetached()) {
// found a discarded/exhausted iterator
probes = LONG_SWEEP_PROBES; // "try harder"
// unlink p
p.clear();
p.next = null;
if (o == null) {
head = next;
if (next == null) {
// We've run out of iterators to track; retire
itrs = null;
return;
}
}
else
o.next = next;
} else {
o = p;
}
p = next;
}
this.sweeper = (p == null) ? null : o;
}
/**
* Adds a new iterator to the linked list of tracked iterators.
*/
void register(Itr itr) {
// assert lock.getHoldCount() == 1;
head = new Node(itr, head);
}
/**
* Called whenever takeIndex wraps around to 0.
*
* Notifies all iterators, and expunges any that are now stale.
*/
void takeIndexWrapped() {
// assert lock.getHoldCount() == 1;
cycles++;
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
final Node next = p.next;
if (it == null || it.takeIndexWrapped()) {
// unlink p
// assert it == null || it.isDetached();
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 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)) {
// unlink p
// assert it == null || it.isDetached();
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() {
// assert lock.getHoldCount() == 1;
for (Node p = head; p != null; p = p.next) {
Itr it = p.get();
if (it != null) {
p.clear();
it.shutdown();
}
}
head = null;
itrs = null;
}
void elementDequeued() {
// assert lock.getHoldCount() == 1;
if (count == 0)
queueIsEmpty();
else if (takeIndex == 0)
takeIndexWrapped();
}
}