併發編程(十三):阻塞隊列之ArrayBlockingQueue

一,關聯源碼鏈接

    * 併發編程(四):AbstractQueuedSynchronizer源碼分析

    * 併發編程(五):AQS之重入鎖ReentrantLock

   * 併發編程(七):AQS之Condition

二,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 實例,從下面名稱可以看出,分別爲 notEmptynotFull。在對數組元素進行操作時,讀元素或者寫寫元素成功後,會默認出發一次 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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章