一,關聯源碼鏈接
* 併發編程(四):AbstractQueuedSynchronizer源碼分析
* 併發編程(五):AQS之重入鎖ReentrantLock
二,ArrayBlockingQueue 概述
1,ArrayBlockingQueue
ArrayBlockingQueue 是通過數組實現的FIFO(先進先出)有界阻塞隊列,數組長度在初始化時指定並固定,不存在數組擴容。ArrayBlockingQueue 內部通過重入鎖 ReentrantLock 進行線程加鎖,保證數據原子性。阻塞及釋放通過兩個 Condition 構成 notEmpty 和 notFull 兩個實例,通過 Condition 線程通信實現加數據和取數據的線程阻塞及線程喚醒。ArrayBlockingQueue 元素獲取基於指針操作,內部維護 putIndex 和 takeIndex 兩個指針,對於移除元素操作和添加元素元素都由着兩個指針控制操作索引,並順序後移,具體源碼分析;
2,類圖
3,常用API
// 初始化,通過構造器重載處理
public ArrayBlockingQueue(int capacity);
ArrayBlockingQueue(int capacity, boolean fair);
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c);
// 取元素:
// 獲取當前元素,不阻塞,不移動指針
public E peek();
// 獲取當前元素,隊列爲空返回null,隊列不爲空返回元素,獲取後移除
public E poll();
// 獲取當前元素,隊列爲空阻塞,不爲空返回元素,獲取後移除
public E take() throws InterruptedException;
// 寫元素:
// 添加元素到隊列,隊列未滿插入成功,隊列滿了直接拋異常
public boolean add(E e);
// 添加元素到隊列,隊列未滿插入成功,隊列滿了插入失敗,返回true/false
public boolean offer(E e);
// 添加元素到隊列,隊列未滿插入成功,隊列滿了阻塞插入
public void put(E e) throws InterruptedException;
// 移除元素
public boolean remove(Object o);
public boolean removeAll(Collection<?> c);
// 迭代器部分
// 構建迭代
public Iterator<E> iterator();
// 迭代_是否存在下一個
public boolean hasNext();
// 迭代_獲取下一個
public E next();
// 迭代_移除
public void remove();
4,功能DEMO
* 此處只是簡單演示元素插入和元素獲取,以及元素插入和獲取關聯影響到的阻塞處理
package com.asdc.mtTest_1;
import javax.swing.*;
import java.util.concurrent.ArrayBlockingQueue;
/**
* @author LiYanBin
* @create 2019-10-23 17:57
**/
public class ArrayBlockTest {
public static void main(String[] args) throws InterruptedException {
ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);
new Thread(() -> {
try {
arrayBlockingQueue.add("add方式");
System.out.println("獲取不移除:" + arrayBlockingQueue.peek());
System.out.println("獲取並移除:" + arrayBlockingQueue.poll());
System.out.println("阻塞獲取前:" + System.currentTimeMillis());
System.out.println("阻塞獲取:" + arrayBlockingQueue.take());
System.out.println("阻塞獲取後:" + System.currentTimeMillis());
// 沉睡足夠時間,等待線程2阻塞插入等待後,消費一次,讓阻塞插入成功
Thread.sleep(5000);
System.out.println("獲取元素,釋放阻塞插入:" + arrayBlockingQueue.take());
System.out.println("獲取阻塞插入元素:" + arrayBlockingQueue.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Thread.sleep(3000);
new Thread(() -> {
try {
System.out.println("添加元素,滿後拋異常:" + arrayBlockingQueue.add("add方式"));
System.out.println("add元素被阻塞獲取獲取後並釋放,則offer爲true");
System.out.println("添加元素,未滿返回true,滿後返回false:" + arrayBlockingQueue.offer("offer方式"));
System.out.println("阻塞插入前," + System.currentTimeMillis());
arrayBlockingQueue.put("put方式");
System.out.println("阻塞插入後," + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
}
二,鎖操作及指針操作
1,鎖操作
1.1,加鎖處理:ReentrantLock
* ArrayBlockingQueue 通過重入鎖保證原子性操作。在每一次數組元素操作時,都進行加鎖和釋放鎖處理
final ReentrantLock lock;
1.2,線程通信:Condition
* ArrayBlockingQueue 內部定義了兩個 Condition 實例,從下面名稱可以看出,分別爲 notEmpty 和 notFull。在對數組元素進行操作時,讀元素或者寫寫元素成功後,會默認出發一次 notEmpty/notFull.signal(),喚醒一個等待線程進行元素插入或者元素消費。同樣,在讀元素或者取元素時,如果數據已滿或者數據爲空,則會觸發 notEmpty/notFull.await() 進行等待,等待元素或者元素消費後進行線程喚醒
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;
2,指針操作
* ArrayBlockingQueue 雖然底層也是數組形式,但是和 ArrayList 的元素讀取還是有所區別。ArrayBlockingQueue 內部元素排列也是連續性的,但是這個連續性是對於一段下標區間的。元素的插入和移除相對應的會對 takeIndex 和 putIndex 指針進行遞增操作,而下一次插入或者移除繼續從指針位置開始。比如,對於一個空 ArrayBlockingQueue 隊列來講,第一次插入元素默認 putIndex 爲0,則添加到0下標位置,同時 putIndex++。此時如果存在線程進行數據移除,而 takeIndex 同樣爲0,則移除0下標的元素,同時 takeIndex++。這時候繼續添加元素,putIndex 已經修改爲1,則添加元素到1下標位置,後續操作相同。這時候數組形態就是0下標爲null,1下標有元素,後續皆爲null。所以元素讀寫是一個連續的過程,而元素移除後,同樣會對後續部分整體前移,並修改讀寫指針;
/** items index for next take, poll, peek or remove */
int takeIndex;
/** items index for next put, offer, or add */
int putIndex;
三,源碼分析
1,讀源碼分析
1.1,peek():獲取當前指針元素,不阻塞,不移動指針,存在返回元素,不存在返回null
* peek()
public E peek() {
// 加鎖釋放鎖操作
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 根據讀索引獲取索引位置元素
return itemAt(takeIndex);
} finally {
lock.unlock();
}
}
* itemAt(int i):返回位置元素,不存在則爲null
final E itemAt(int i) {
return (E) items[i];
}
1.2,poll():獲取當前指針元素,數組爲空返回null,數組不爲空返回當前指針元素並移除該元素,指針後移
* poll()
public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 數組爲空返回null,不爲空獲取元素
// dequeue:爲獲取數據底層方法
return (count == 0) ? null : dequeue();
} finally {
lock.unlock();
}
}
* dequeue():元素讀取底層方法
private E dequeue() {
final Object[] items = this.items;
// 從數據中獲取讀指針下標元素
E x = (E) items[takeIndex];
// 獲取並移除在此處體現,讀取到後直接置null
items[takeIndex] = null;
// 讀指針獲取完成後,直接遞增,如果已經指向最後一個下標,則回到第一個下標
if (++takeIndex == items.length)
takeIndex = 0;
// 數據元素數量遞減
count--;
// 此處迭代器操作,後續迭代器分析
if (itrs != null)
itrs.elementDequeued();
// 元素讀取並移除後,元素必定未滿,喚醒notFull線程,允許元素插入
notFull.signal();
// 返回元素
return x;
}
1.3,take():獲取當前指針元素,數組爲空阻塞,數組不爲空獲取當前指針元素並移除該元素,指針後移
* take()
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
// take方法爲空阻塞在此處阻塞,數組元素數量爲空,notEmpty線程等待
// 等待數組存在數據插入時,會喚醒該方法
while (count == 0)
notEmpty.await();
// 取數據
return dequeue();
} finally {
lock.unlock();
}
}
2,寫源碼分析
2.1,add(E e):添加元素,數組滿了拋異常,數組未滿添加到指針位置
* add()
public boolean add(E e) {
// 向上調用父類方法
return super.add(e);
}
// java.util.AbstractQueue#add
public boolean add(E e) {
// 內部調用offer方法,插入成功返回true
// 插入失敗直接拋異常
if (offer(e))
return true;
else
throw new IllegalStateException("Queue full");
}
2.2,offer(E e):添加元素,數據滿了返回false,數組未滿返回true
* offer(E e)
public boolean offer(E e) {
// null值校驗,此處爲null直接拋空指針異常
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 數組已滿,返回false
if (count == items.length)
return false;
else {
// 數據未滿,寫數據
enqueue(e);
return true;
}
} finally {
lock.unlock();
}
}
* enqueue(E x):元素入列,此爲底層方法
private void enqueue(E x) {
// 獲取元素,並添加元素到寫指針位置
final Object[] items = this.items;
items[putIndex] = x;
// 寫指針到末尾,直接置爲頭索引,並底層
if (++putIndex == items.length)
putIndex = 0;
// 數組元素數量遞增
count++;
// 添加成功後,數組元素不爲空,喚醒等待讀鎖
notEmpty.signal();
}
2.3,put(E e):添加元素,數組滿了阻塞,數據未滿添加成功
* put(E e)
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();
}
}
3,移除源碼分析
3.1,remove(Object o):移除元素,移除成功返回true,失敗返回false
* remove(Object o)
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);
}
// 數組不存在元素,直接返回false
return false;
} finally {
lock.unlock();
}
}
* removeAt(final int removeIndex)
void removeAt(final int removeIndex) {
final Object[] items = this.items;
// 刪除下標等於讀指針,直接把該下標元素置空,並遞增讀指針
if (removeIndex == takeIndex) {
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
// 元素數量遞減
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 {
// 所有元素前移完成後,原最後一個元素置空,並將寫指針置位該位置
// 因爲當前元素已經前移一位
items[i] = null;
this.putIndex = i;
break;
}
}
count--;
if (itrs != null)
itrs.removedAt(removeIndex);
}
notFull.signal();
}
3.2,removeAll(Collection<?> c):移除元素組,移除成功返回true,失敗返回false
* removeAll(Collection<?> c):父類方法,內部通過迭代循環移除,迭代部分分析
public boolean removeAll(Collection<?> c) {
Objects.requireNonNull(c);
boolean modified = false;
// 迭代後循環移除
Iterator<?> it = iterator();
while (it.hasNext()) {
if (c.contains(it.next())) {
it.remove();
modified = true;
}
}
return modified;
}
4,迭代器源碼分析,沒分析清,網上資料也比較少,參考少,後續再補充,只能說比較麻煩,涉及參數和狀態轉變太多
4.1,相關元素
Itr:
// 迭代器下一次迭代的座標,NONE表示沒有
private int cursor;
// 迭代的下一個元素
private E nextItem;
// 迭代的下一個元素下標,null表示-1,被移除表示-2
private int nextIndex;
// 迭代上一個元素
private E lastItem;
// 迭代上一個元素下標,null表示-1,被移除表示-2
private int lastRet;
// 記錄上次迭代的下標,迭代器失效時值爲 DETACHED
private int prevTakeIndex;
// 記錄上次循環次數,和cycles進行對比,可知變化
private int prevCycles;
// 爲null時表示
private static final int NONE = -1;
// 元素被調用remove移除
private static final int REMOVED = -2;
// 迭代器過期
private static final int DETACHED = -3;
Itrs:
// 數組列表循環次數,每一次takeIndex到0時加1
int cycles = 0;
// 頭結點,該鏈表後續添加節點爲頭結點
private Node head;
// 清理失效節點的標識節點
private Node sweeper = null;
// 清理的循環次數
private static final int SHORT_SWEEP_PROBES = 4;
private static final int LONG_SWEEP_PROBES = 16;
4.2,Itr():迭代器初始化
Itr() {
// assert lock.getHoldCount() == 0;
lastRet = NONE;
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// 數組元素爲空,進行參數初始化
if (count == 0) {
cursor = NONE;
nextIndex = NONE;
prevTakeIndex = DETACHED;
} else {
// 當前讀指針位置
final int takeIndex = ArrayBlockingQueue.this.takeIndex;
// 賦值上一次的讀指針,該指針位置內部定義,有Itr內部控制
prevTakeIndex = takeIndex;
// 賦值下一個節點元素,初始化時賦值爲第一個
nextItem = itemAt(nextIndex = takeIndex);
// 獲取下一次迭代座標,有下一個元素爲下一個元素索引,沒有返回-1
cursor = incCursor(takeIndex);
// 判斷itrs是否已經初始化,未初始化則初始化,初始化則註冊
// 此處設計思想有點類似與ThreadLocal
// 每一個 AarrayBlockingQueue 可以初始化多個迭代器,每一個迭代器即Itr在Itrs中以Node的形式存在,
// Itr被包裝爲弱引用,在GC時如果沒有強引用對象關聯,則會被回收掉
if (itrs == null) {
itrs = new Itrs(this);
} else {
itrs.register(this);
// 註冊完成後對Itrs內的Node節點做清理
itrs.doSomeSweeping(false);
}
prevCycles = itrs.cycles;
}
} finally {
lock.unlock();
}
}
* incCursor(int index):獲取下一個迭代位置
private int incCursor(int index) {
// 默認迭代位置是當前索引的下一個位置
// 如果當前索引位置與寫指針位置重複,即沒有後續節點,直接返回-1
if (++index == items.length)
index = 0;
if (index == putIndex)
index = NONE;
return index;
}
* register(initial):初始化 Itrs 及註冊當前迭代器 Itr
// 初始化Itrs
Itrs(Itr initial) {
register(initial);
}
// 註冊迭代器到Itrs
void register(Itr itr) {
// 直接構造爲頭結點,其他節點依次掛next節點
// 該鏈表會把後續的節點掛在上游節點,即後來居上
head = new Node(itr, head);
}
* doSomeSweeping(boolean tryHarder):Itrs 數據清理,如果存在清理標識,從標識清理;不存在,在全鏈表清理
void doSomeSweeping(boolean tryHarder) {
// 此處獲取清理次數
int probes = tryHarder ? LONG_SWEEP_PROBES : SHORT_SWEEP_PROBES;
// o 節點表示 p 節點的上一個節點
Node o, p;
// 獲取清理節點表示
final Node sweeper = this.sweeper;
// 根據sweeper判斷的標誌位
boolean passedGo;
// sweeper 爲空,則全表掃描清理,o賦null值,p賦頭值
// sweeper 不爲空,非全表掃描,o賦sweep值,p表示下一個節點
if (sweeper == null) {
o = null;
p = head;
passedGo = true;
} else {
o = sweeper;
p = o.next;
passedGo = false;
}
// 按照指定的循環次數循環
for (; probes > 0; probes--) {
// p節點爲空,表示頭結點或者o節點即清理節點的下一個節點爲空
if (p == null) {
// passedGo爲true,表示p爲頭節點,頭結點爲空,直接跳出循環
if (passedGo)
break;
// 表示p爲清理節點的下一個節點,爲空重置頭頭結點
o = null;
p = head;
passedGo = true;
}
// 獲取節點處理的Itr迭代器,及下一個節點
final Itr it = p.get();
final Node next = p.next;
// 如果迭代器爲null(GC)回收
// 或者迭代器已經過期(存在數據操作)進行數據清理
if (it == null || it.isDetached()) {
// 重置次數爲最大次數
probes = LONG_SWEEP_PROBES;
// 清理p節點,並重新關聯o節點,
p.clear();
p.next = null;
if (o == null) {
head = next;
// 如果不存在o節點也不存在下一個節點,則Itrs內沒有數據,直接置空
if (next == null) {
itrs = null;
return;
}
}
else
o.next = next;
} else {
// 節點未失效,繼續向下尋找
o = p;
}
p = next;
}
// 定義清理標識位置
this.sweeper = (p == null) ? null : o;
}
* isDetached():迭代器過期判斷
boolean isDetached() {
// prevTakeIndex小於0,說明線程已經對數據進行變更,並將該迭代器的狀態置位過期
return prevTakeIndex < 0;
}
4.3,elementDequeued():takeIndex變更引起的變更處理
* elementDequeued():取數據觸發
void elementDequeued() {
// 隊列中元素爲空,進行空處理
if (count == 0)
queueIsEmpty();
// 讀指針爲0,說明已經走過一次循環
else if (takeIndex == 0)
takeIndexWrapped();
}
* queueIsEmpty()
void queueIsEmpty() {
// 對Itrs進行置null
// Itrs內部包裝節點Node進行清空並關閉
for (Node p = head; p != null; p = p.next) {
Itr it = p.get();
if (it != null) {
p.clear();
it.shutdown();
}
}
head = null;
itrs = null;
}
* takeIndexWrapped()
// java.util.concurrent.ArrayBlockingQueue.Itrs#takeIndexWrapped
void takeIndexWrapped() {
cycles++;
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;
else
o.next = next;
} else {
o = p;
}
p = next;
}
if (head == null) // no more iterators to track
itrs = null;
}
4.4,hasNext():判斷下一個元素
* hasNext()
public boolean hasNext() {
// Itr初始化時,已經對nextItem進行賦值,如果不爲空,說明存在,返回true
if (nextItem != null)
return true;
// 下一個節點不存在處理
noNext();
return false;
}
* noNext()
private void noNext() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// 判斷當前迭代器是否已經過期
// 沒有過期繼續操作
if (!isDetached()) {
// 判斷元素是否發生移動,移動後判斷是否過期及對應參數重新賦值
incorporateDequeues();
if (lastRet >= 0) {
// 獲取上一個迭代元素,並失效當前Itr
lastItem = itemAt(lastRet);
detach();
}
}
} finally {
lock.unlock();
}
}
* incorporateDequeues()
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;
// 獲取數據偏移量
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;
}
}
}
* invalidated(int index, int prevTakeIndex, long dequeues, int length):失效算法判斷,目前沒搞懂
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;
}
4.5,next():獲取下一個元素
public E next() {
// 迭代器初始化後,如果此時將隊列清空,因爲nextItem已經初始化,此時依舊會返回初始化迭代時候的第一個元素
// 下一個元素不存在,直接空指針
final E x = nextItem;
if (x == null)
throw new NoSuchElementException();
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// 迭代器未失效,進行數據偏移矯正或者直接失效
if (!isDetached())
incorporateDequeues();
// 重置上一個節點及下一個節點的下標和元素
lastRet = nextIndex;
final int cursor = this.cursor;
// 存在下一個座標
if (cursor >= 0) {
nextItem = itemAt(nextIndex = cursor);
// 下一次迭代座標遞增
this.cursor = incCursor(cursor);
// 不存在下一個座標,直接對相關元素置空
} else {
nextIndex = NONE;
nextItem = null;
}
} finally {
lock.unlock();
}
return x;
}
4.6,remove():移除當前元素
* remove()
public void remove() {
final ReentrantLock lock = ArrayBlockingQueue.this.lock;
lock.lock();
try {
// 如果沒有過期,進行元素位置矯正
if (!isDetached())
incorporateDequeues();
// 獲取上一個獲取的元素座標
// Itr初始化時候,lastRet已經初始化爲-1
// 調用next():會對lastRet進行重賦值,賦當時的next值
final int lastRet = this.lastRet;
this.lastRet = NONE;
// lastRet >= 0,說明已經調用next初始化
if (lastRet >= 0) {
// Itr沒有過期,直接移除
if (!isDetached())
// 調用ArrayBlockingQueue移除
removeAt(lastRet);
else {
// Itr已經過期,對lastItem進行處理
final E lastItem = this.lastItem;
this.lastItem = null;
if (itemAt(lastRet) == lastItem)
removeAt(lastRet);
}
// 爲NONE,說明沒有初始化
} else if (lastRet == NONE)
throw new IllegalStateException();
// 不存在下一個元素,直接失效
if (cursor < 0 && nextIndex < 0)
detach();
} finally {
lock.unlock();
}
}
* removedAt(int removedIndex):調用Itrs移除
// java.util.concurrent.ArrayBlockingQueue.Itrs#removedAt
void removedAt(int removedIndex) {
// 遍歷Itrs中整串Itr
for (Node o = null, p = head; p != null;) {
final Itr it = p.get();
final Node next = p.next;
// Itr 爲null,說明已經被GC回收,直接清空回收處理
// Itr不爲空,判斷是否可以移除
if (it == null || it.removedAt(removedIndex)) {
p.clear();
p.next = null;
if (o == null)
head = next;
else
o.next = next;
} else {
o = p;
}
p = next;
}
// head爲null,說明已經遍歷完成,則直接置空Itrs
if (head == null)
itrs = null;
}
* removedAt(int removedIndex):調用Itr判斷是否可以移除,沒懂,有空再分析吧
// java.util.concurrent.ArrayBlockingQueue.Itr#removedAt
boolean removedAt(int removedIndex) {
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);
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) {
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;
}