目錄
8、queueIsEmpty / elementDequeued / takeIndexWrapped / removedAt
ArrayBlockingQueue表示一個基於數組實現的固定容量的,先進先出的,線程安全的隊列(棧),本篇博客就詳細講解該類的實現細節。
1、定義
ArrayBlockingQueue的類繼承關係如下:
其核心接口BlockingQueue包含的方法定義如下:
上圖中的Queue和Collection下面都有兩個接口,這兩個接口是BlockingQueue覆寫的,並不是說這兩類只有這兩接口,Collection和Queue的主要接口實現都由AbstractQueue實現了,我們重點關注上圖中列出來的這些接口的實現。
ArrayBlockingQueue包含的屬性如下:
/**保存隊列元素的數組 */
final Object[] items;
/** items index for next take, poll, peek or remove */
int takeIndex;
/** offer,add,put等方法將元素保存到該索引處 */
int putIndex;
/** 隊列中元素的個數 */
int count;
/** 互斥鎖*/
final ReentrantLock lock;
/** 如果數組是空的,在該Condition上等待 */
private final Condition notEmpty;
/** 如果數組是滿的,在該Condition上等待 */
private final Condition notFull;
/** 遍歷器實現 */
transient Itrs itrs = null;
重點關注以下方法的實現。
2、構造方法
public ArrayBlockingQueue(int capacity) {
this(capacity, false);
}
//capacity表示隊列的容量,fair表示是否使用公平鎖
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);
final ReentrantLock lock = this.lock;
//加鎖的目的是爲了其他CPU能夠立即看到修改
//加鎖和解鎖底層都是CAS,會強制修改寫回主存,對其他CPU可見
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();
}
}
3、add / offer / put
這三個方法都是往隊列中添加元素,說明如下:
- add方法依賴於offer方法,如果隊列滿了則拋出異常,否則添加成功返回true;
- offer方法有兩個重載版本,只有一個參數的版本,如果隊列滿了就返回false,否則加入到隊列中,返回true,add方法就是調用此版本的offer方法;另一個帶時間參數的版本,如果隊列滿了則等待,可指定等待的時間,如果這期間中斷了則拋出異常,如果等待超時了則返回false,否則加入到隊列中返回true;
- put方法跟帶時間參數的offer方法邏輯一樣,不過沒有等待的時間限制,會一直等待直到隊列有空餘位置了,再插入到隊列中,返回true
public boolean add(E e) {
//調用子類offer方法實現,如果隊列滿了則拋出異常
return super.add(e);
}
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();
}
}
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();
}
}
//同上面的put方法,只不過可以指定等待的時間
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();
}
}
public boolean add(E e) {
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
private void enqueue(E x) {
final Object[] items = this.items;
//保存到putIndex索引處
items[putIndex] = x;
//數組滿了,將其重置爲0
if (++putIndex == items.length)
putIndex = 0;
//數組元素個數增加
count++;
//喚醒因爲隊列是空的而等待的線程
notEmpty.signal();
}
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
4、poll / take / peek
這幾個方法都是獲取隊列頂的元素,具體說明如下:
- poll方法有兩個重載版本,第一個版本,如果隊列是空的,返回null,否則移除並返回隊列頭部元素;另一個帶時間參數的版本,如果棧爲空則等待,可以指定等待的時間,如果等待超時了則返回null,如果被中斷了則拋出異常,否則移除並返回棧頂元素
- take方法同帶時間參數的poll方法,但是不能指定等待時間,會一直等待直到隊列中有元素爲止,然後移除並返回棧頂元素
- peek方法只是返回隊列頭部元素,不移除
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//如果爲空,返回null,否則取出一個元素
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//如果空的,則等待
while (count == 0)
notEmpty.await();
//取出一個元素
return dequeue();
} finally {
lock.unlock();
}
}
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; //等待超時,返回null
//數組爲空,等待
nanos = notEmpty.awaitNanos(nanos);
}
return dequeue();
} finally {
lock.unlock();
}
}
public E peek() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
//返回棧頂元素,takeIndex值不變
return itemAt(takeIndex); // null when queue is empty
} finally {
lock.unlock();
}
}
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
//取出takeIndex的元素,將其置爲null
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;//取完了,從頭開始取
count--;
if (itrs != null)
//通知itrs棧頂的元素被移除了
itrs.elementDequeued();
//喚醒因爲棧滿了等待的線程
notFull.signal();
return x;
}
final E itemAt(int i) {
return (E) items[i];
}
5、remove / clear /drainTo
這三個方法用於從隊列中移除元素,具體說明如下:
- remove方法用於移除某個元素,如果棧爲空或者沒有找到該元素則返回false,否則從棧中移除該元素;移除時,如果該元素位於棧頂則直接移除,如果位於棧中間,則需要將該元素後面的其他元素往前面挪動,移除後需要喚醒因爲棧滿了而阻塞的線程
- clear方法用於整個棧,同時將takeIndex置爲putIndex,保證棧中的元素先進先出;最後會喚醒最多count個線程,因爲正常一個線程插入一個元素,如果喚醒超過count個線程,可能導致部分線程因爲棧滿了又再次被阻塞
- drainTo方法有兩個重載版本,一個是不帶個數,將所有的元素都移除並拷貝到指定的集合中;一個帶個數,將指定個數的元素移除並拷貝到指定的集合中,兩者的底層實現都是同一個方法。移除後需要重置takeIndex和count,並喚醒最多移除個數的因爲棧滿而阻塞的線程。
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;
//從takeIndex開始往後遍歷直到等於putIndex
do {
if (o.equals(items[i])) {
//找到目標元素,將其移除
removeAt(i);
return true;
}
//走到數組末尾了又從頭開始,put時也按照這個規則來
if (++i == items.length)
i = 0;
} while (i != putIndex);
}
//如果數組爲空,返回false
return false;
} finally {
lock.unlock();
}
}
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;
//從takeIndex開始遍歷直到i等於putIndex,將數組元素置爲null
do {
items[i] = null;
if (++i == items.length)
i = 0;
} while (i != putIndex);
//注意此處沒有將這兩個index置爲0,只是讓他們相等,因爲只要相等就可以實現棧先進先出了
takeIndex = putIndex;
count = 0;
if (itrs != null)
itrs.queueIsEmpty();
//如果有因爲棧滿了而等待的線程,則將其喚醒
//注意這裏沒有使用signalAll而是通過for循環來signal多次,單純從喚醒線程來看是可以使用signalAll的,效果跟這裏的for循環是一樣的
//如果有等待的線程,說明count就是當前線程的最大容量了,這裏清空了,最多隻能put count次,一個線程只能put 1次,只喚醒最多count個線程就避免了
//線程被喚醒後再次因爲棧滿了而阻塞
for (; k > 0 && lock.hasWaiters(notFull); k--)
notFull.signal();
}
} finally {
lock.unlock();
}
}
public int drainTo(Collection<? super E> c) {
return drainTo(c, Integer.MAX_VALUE);
}
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 {
//從takeIndex開始遍歷,取出元素然後添加到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 {
// Restore invariants even if c.add() threw
if (i > 0) {
//取完了,修改count減去i
count -= i;
takeIndex = take;
if (itrs != null) {
if (count == 0)
//通知itrs 棧空了
itrs.queueIsEmpty();
else if (i > take)
//說明take中間變成0了,通知itrs
itrs.takeIndexWrapped();
}
//喚醒在因爲棧滿而等待的線程,最多喚醒i個,同上避免線程被喚醒了因爲棧又滿了而阻塞
for (; i > 0 && lock.hasWaiters(notFull); i--)
notFull.signal();
}
}
} finally {
lock.unlock();
}
}
void removeAt(final int removeIndex) {
final Object[] items = this.items;
if (removeIndex == takeIndex) {
//如果移除的就是棧頂的元素
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
//元素個數減1
count--;
if (itrs != null)
itrs.elementDequeued();
} else {
//如果移除的是棧中間的某個元素,需要將該元素後面的元素往前挪動
final int putIndex = this.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 {
//如果下一個元素的索引等於putIndex,說明i就是棧中最後一個元素了,直接將該元素置爲null
items[i] = null;
//重置putIndex爲i
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
//通知itrs節點移除了
itrs.removedAt(removeIndex);
}
//喚醒因爲棧滿了而等待的線程
notFull.signal();
}
6、iterator / Itr / Itrs
iterator方法返回一個迭代器實例,用於實現for循環遍歷和部分Collection接口,該方法的實現如下:
public Iterator<E> iterator() {
return new Itr();
}
Itr() {
// assert lock.getHoldCount() == 0;
lastRet = NONE;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
if (count == 0) {
//NONE和DETACHED都是常量
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,將當前線程註冊到Itrs
itrs = new Itrs(this);
} else {
//將當前線程註冊到Itrs中,並執行清理
itrs.register(this); // in this order
itrs.doSomeSweeping(false);
}
prevCycles = itrs.cycles;
}
} finally {
lock.unlock();
}
}
Itrs(Itr initial) {
register(initial);
}
//根據index計算cursor
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
if (++index == items.length)
index = 0;
if (index == putIndex)
index = NONE;
return index;
}
void register(Itr itr) {
head = new Node(itr, head);
}
Itr和Itrs都是ArrayBlockingQueue的兩個內部類,Itr包含的屬性如下:
/** 查找下一個nextItem的索引,如果是NONE表示到棧底了*/
private int cursor;
/** 下一次調用next()方法返回的元素,初始值爲takeIndex對應的元素 */
private E nextItem;
/**nextItem元素對應的索引,如果是NONE表示nextItem是null, 如果是REMOVED表示nextItem被移除了,初始值就等於takeIndex*/
private int nextIndex;
/**上一次被返回的元素,如果*/
private E lastItem;
/**lastItem對應的索引 */
private int lastRet;
/**Itr初始化時takeIndex的值 */
private int prevTakeIndex;
/**Itr初始化時iters.cycles的值 */
private int prevCycles;
/** 特殊的索引值,表示這個索引對應的元素不存在 */
private static final int NONE = -1;
/** 特殊的索引值,表示該索引對應的元素已經被移除了 */
private static final int REMOVED = -2;
/** 特殊的prevTakeIndex值,表示當前Iter已經從Iters中解除關聯了 */
private static final int DETACHED = -3;
Itrs包含的屬性如下:
/**當takeIndex變成0以後加1 */
int cycles = 0;
/** Iter實例鏈表的鏈表頭 */
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;
其中Node爲Itrs的一個內部類,其定義如下:
注意Node繼承自WeakReference。
7、doSomeSweeping / register
Itrs內部維護了一個Itr實例鏈表,register方法用於將一個新的Itr實例加入到鏈表頭,doSomeSweeping方法用於清除該鏈表中無效的Itr實例,查找這類實例是通過for循環實現的,初始for循環的次數是通過參數tryHandler控制的,如果爲true,則循環16次,如果爲false,則循環4次,在循環的過程中找到了一個無效的Itr實例,則需要再遍歷16次,直到所有節點都遍歷完成。注意這裏的無效指的這個Itr實例已經同Itrs datached了,當ArrayBlockingQueue執行Itrs的回調方法時就不會處理這種Itr實例了,即Itr實例無法感知到ArrayBlockingQueue的改變了,這時基於Itr實例遍歷的結果可能就不準確了。
//創建一個新的Itr實例時,會調用此方法將該實例添加到Node鏈表中
void register(Itr itr) {
//創建一個新節點將其插入到head節點的前面
head = new Node(itr, head);
}
//用於清理那些陳舊的Node
void doSomeSweeping(boolean tryHarder) {
// assert lock.getHoldCount() == 1;
// assert head != null;
//probes表示循環查找的次數
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
//o表示上一個有效節點,p表示當前遍歷的節點,如果o爲空,則p是head,否則是o的下一個節點
//進入此方法,sweeper可能爲null,head不會爲null
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; //sweeper爲null時,passedGo爲true,終止循環,將sweeper賦值
//passedGo爲false,sweeper不爲null,因爲p爲null,還是將其置爲true,即只能循環一次
o = null;
p = head;
passedGo = true;
}
//獲取關聯的Itr
final Itr it = p.get();
final Node next = p.next;
if (it == null || it.isDetached()) {
//如果it爲null或者已經解除關聯了
//只要找到了一個無效節點,則需要再遍歷LONG_SWEEP_PROBES次,直到所有節點遍歷完爲止
probes = LONG_SWEEP_PROBES; // "try harder"
//將關聯的Itr置爲null
p.clear();
p.next = null;
if (o == null) { //sweeper爲null或者sweeper的next爲null時
//沒有找到有效節點,重置head,將next之前的節點都移除
head = next;
if (next == null) {
//next爲null,沒有待處理的節點了,所以Itr都退出了,將itrs置爲null
itrs = null;
return;
}
}
else
//將next作爲o的下一個節點,即將p移除了
o.next = next;
} else {
//p對應的Itr實例是有效的,將o置爲p
o = p;
}
//處理下一個節點
p = next;
}
//重置sweeper,p等於null說明節點都遍歷完了,sweeper爲null
//如果p不等於null,說明還有未遍歷的節點,將sweeper置爲0,下一次遍歷時可以重新從該節點開始遍歷
this.sweeper = (p == null) ? null : o;
}
boolean isDetached() {
// assert lock.getHoldCount() == 1;
return prevTakeIndex < 0;
}
8、queueIsEmpty / elementDequeued / takeIndexWrapped / removedAt
這四個方法都是在某種條件下,由ArrayBlockingQueue回調Itrs的方法,具體如下:
- queueIsEmpty方法用於因爲元素移除棧空了時調用的,會將Itr鏈表中的所有元素對Itr實例的引用置爲null,將Itr實例的各屬性置爲null或者特殊index值
- takeIndexWrapped方法用於takeIndex變成0了後調用,會增加cycles計數,如果當前cycles屬性減去Itr實例的prevCycles屬性大於1,則說明Itr初始化時棧中的元素都被移除了,此時再遍歷無意義,將這類節點從Itr實例鏈表中移除,將對Itr的引用置爲null,將Itr實例的各屬性置爲null或者特殊index值
- removedAt方法用於從棧中注意不是棧頂移除元素時調用的,會重新計算cursor,lastRet,nextIndex等屬性,如果計算出來的屬性小於0,則將這個節點從Itr實例鏈表中移除,將Itr實例的各屬性置爲null或者特殊index值
- elementDequeued方法時元素從棧頂移除時調用,如果當前棧空了則調用queueIsEmpty方法,如果takeIndex變成0了,則調用takeIndexWrapped方法
//從棧頂移除一個元素時回調的
void elementDequeued() {
// assert lock.getHoldCount() == 1;
if (count == 0)
//如果棧空了
queueIsEmpty();
else if (takeIndex == 0)
takeIndexWrapped();
}
//棧變成空的以後回調此方法
void queueIsEmpty() {
// assert lock.getHoldCount() == 1;
//遍歷鏈表
for (Node p = head; p != null; p = p.next) {
Itr it = p.get();
if (it != null) {
//將引用清除
p.clear();
//通知Itr隊列空了,將各參數置爲null或者特殊index值
it.shutdown();
}
}
//重置爲null
head = null;
itrs = null;
}
//當takeIndex變成0的時候回調的
void takeIndexWrapped() {
// assert lock.getHoldCount() == 1;
cycles++;
//遍歷鏈表,o表示上一個有效節點,p表示當前遍歷的節點
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
final Node next = p.next;
if (it == null || it.takeIndexWrapped()) {
p.clear();
p.next = null;
if (o == null)
//之前的節點是無效節點,重置head,把next之前的節點都移除了
head = next;
else
//移除p這一個節點
o.next = next;
} else {
//保存上一個有效節點
o = p;
}
//處理下一個節點
p = next;
}
//沒有有效節點,itrs置爲null
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;
//removedAt方法判斷這個節點是否被移除了
if (it == null || it.removedAt(removedIndex)) {
//將p從鏈表中移除
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;
}
//判斷Itr這個節點是否應該被移除
boolean takeIndexWrapped() {
// assert lock.getHoldCount() == 1;
if (isDetached())
return true;
if (itrs.cycles - prevCycles > 1) {
// cycles不一致了,則原來棧中的元素可能都沒了
shutdown();
return true;
}
return false;
}
void shutdown() {
// assert lock.getHoldCount() == 1;
//nextItem沒有被置爲null,通過next方法還可以返回
cursor = NONE;
if (nextIndex >= 0)
nextIndex = REMOVED;
if (lastRet >= 0) {
lastRet = REMOVED;
lastItem = null;
}
prevTakeIndex = DETACHED;
}
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;
//按照特定的邏輯重新計算cursor,lastRet,nextIndex等屬性
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;
}
private int distance(int index, int prevTakeIndex, int length) {
int distance = index - prevTakeIndex;
if (distance < 0)
distance += length;
return distance;
}
9、next / hasNext / remove
這三個方法時Itr對Iterator接口的實現,如下:
public boolean hasNext() {
// assert lock.getHoldCount() == 0;
if (nextItem != null)
return true;
//如果沒有下一個元素了
noNext();
return false;
}
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();
//如果isDetached爲true還會繼續執行
// assert nextIndex != NONE;
// assert lastItem == null;
lastRet = nextIndex;
final int cursor = this.cursor;
if (cursor >= 0) {
//獲取指定cursor的元素
nextItem = itemAt(nextIndex = cursor);
//重新計算cursor,如果等於putIndex就將其置爲None
this.cursor = incCursor(cursor);
} else {
//已經遍歷到putIndex處了,上次incCursor計算時將其變成負值
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())
//移除lastRet處的元素
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();
if (cursor < 0 && nextIndex < 0)
detach(); //將當前Itr標記爲無效並嘗試清理掉
} finally {
lock.unlock();
}
}
private void noNext() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// assert cursor == NONE;
// assert nextIndex == NONE;
if (!isDetached()) {
//如果當前Itr還是有效的
incorporateDequeues(); // might update lastRet
if (lastRet >= 0) {
lastItem = itemAt(lastRet);
// assert lastItem != null;
detach();
}
}
} finally {
lock.unlock();
}
}
boolean isDetached() {
// assert lock.getHoldCount() == 1;
return prevTakeIndex < 0;
}
//校驗並調整相關屬性
private void incorporateDequeues() {
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);
//校驗各屬性是否有效
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;
}
}
}
//校驗這個index是否有效,返回true表示無效
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;
}
private void detach() {
if (prevTakeIndex >= 0) {
//將當前Itr標記爲無效的
prevTakeIndex = DETACHED;
//嘗試將當前Itr從鏈表中移除
itrs.doSomeSweeping(true);
}
}
private int incCursor(int index) {
// assert lock.getHoldCount() == 1;
if (++index == items.length)
index = 0;
if (index == putIndex)
index = NONE;
return index;
}