前言
一種阻塞隊列,插入操作必須要有對應的刪除操作正在執行,反之亦然。它沒有任何容量。不能執行peek()操作。不能迭代。適用於線程間的傳遞,一個線程向另一個線程傳遞一些信息、事件、或者任務等。支持公平(FIFO)和非公平模式(LIFO),默認是非公平。
(源自對SynchronousQueue官方註釋的解讀)
源碼分析
構造器:
常用方法
-
put(…)
-
offer(…)
-
take(…)
-
poll(…)
-
drainTo(…)
-
drainTo(…, …)
TransferQueue
- QNode
/** Node class for TransferQueue. */
static final class QNode {
volatile QNode next; // next node in queue
volatile Object item; // CAS'ed to or from null
volatile Thread waiter; // to control park/unpark
final boolean isData;
QNode(Object item, boolean isData) {
this.item = item;
this.isData = isData;
}
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
boolean casItem(Object cmp, Object val) {
return item == cmp &&
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
/**
* Tries to cancel by CAS'ing ref to this as item.
*/
void tryCancel(Object cmp) {
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
}
boolean isCancelled() {
return item == this;
}
/**
* Returns true if this node is known to be off the queue
* because its next pointer has been forgotten due to
* an advanceHead operation.
*/
boolean isOffList() {
return next == this;
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long itemOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class<?> k = QNode.class;
itemOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("item"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
- 成員屬性
-
構造器
-
設置頭節點,並取消鏈接
-
設置尾節點
-
設置cleanMe節點
-
傳遞(插入或者獲取)元素
E transfer(E e, boolean timed, long nanos) {
QNode s = null;
boolean isData = (e != null);
for (;;) {
QNode t = tail;
QNode h = head;
/* 未初始化的隊列 */
if (t == null || h == null)
/* 自旋 */
continue;
/* put操作執行語句 */
/* 空隊列或者模式相同 */
if (h == t || t.isData == isData) {
QNode tn = t.next;
/* 讀取時,發生數據不一致 */
if (t != tail)
continue;
if (tn != null) {
/* 原子添加尾節點 */
advanceTail(t, tn);
continue;
}
/* 設置了超時,並且超時時間已過 */
if (timed && nanos <= 0)
return null;
if (s == null)
s = new QNode(e, isData);
/* 原子設置後繼節點 */
if (!t.casNext(null, s))
continue;
/* 將s節點設置爲尾節點 */
advanceTail(t, s);
/* 指定時間內等待s節點完成 */
Object x = awaitFulfill(s, e, timed, nanos);
/* 取消等待 */
if (x == s) {
clean(t, s);
return null;
}
/* 還在隊列中沒有取消鏈接 */
if (!s.isOffList()) {
/* 如果t現在是頭節點,並且設置s節點爲新的頭節點成功,則對s節點取消鏈接 */
advanceHead(t, s);
if (x != null) // and forget fields
s.item = s;
s.waiter = null;
}
return (x != null) ? (E)x : e;
/* take操作執行語句 */
/* 隊列非空,並且隊列元素的模式不相同 */
} else {
QNode m = h.next;
/* 讀取的時候,發生數據不一致 */
if (t != tail || m == null || h != head)
continue;
Object x = m.item;
/* m節點完成了操作或者被取消或者原子設置item失敗 */
if (isData == (x != null) ||
x == m ||
!m.casItem(x, e)) {
/* 如果h現在是頭節點,並且設置m節點爲新的頭節點成功,則對m節點取消鏈接 */
advanceHead(h, m);
continue;
}
/* successfully fulfilled */
advanceHead(h, m);
LockSupport.unpark(m.waiter);
return (x != null) ? (E)x : e;
}
}
}
- 自旋或者阻塞,直到waiter設置爲當前線程
Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
/* Same idea as TransferStack.awaitFulfill */
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
int spins = ((head.next == s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
for (;;) {
if (w.isInterrupted())
s.tryCancel(e);
Object x = s.item;
if (x != e)
return x;
if (timed) {
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
s.tryCancel(e);
continue;
}
}
if (spins > 0)
--spins;
else if (s.waiter == null)
s.waiter = w;
else if (!timed)
LockSupport.park(this);
else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
核心處理,我個人覺得就只有兩行
Object x = s.item;
if (x != e) return x;
- 清理節點
void clean(QNode pred, QNode s) {
s.waiter = null;
while (pred.next == s) {
QNode h = head;
QNode hn = h.next;
/* 1. 如果要清理的節點是頭節點的後繼節點 */
if (hn != null && hn.isCancelled()) {
advanceHead(h, hn);
continue;
}
QNode t = tail;
/* 如果此時隊列爲空 */
if (t == h)
return;
QNode tn = t.next;
if (t != tail)
continue;
/* 說明有其他線程在隊列尾部添加了新節點 */
if (tn != null) {
/* 原子方式設置尾節點 */
advanceTail(t, tn);
continue;
}
/* 2. 如果要清理的節點是中間節點 */
if (s != t) {
QNode sn = s.next;
/* 修改完畢 或者 成功cas設置其後繼節點 */
if (sn == s || pred.casNext(s, sn))
return;
}
/* 3. 如果要清理的節點是尾節點 */
/* 獲取上一次標記爲cleanMe的節點 */
QNode dp = cleanMe;
if (dp != null) { // Try unlinking previous cancelled node
QNode d = dp.next;
QNode dn;
if (d == null || // 還沒有後繼節點添加 或者
d == dp || // 有後繼節點添加,但是它已經離隊 或者
!d.isCancelled() || // 有後繼節點添加,它沒有被取消 或者
(d != t && // d不是尾節點 並且
(dn = d.next) != null && // d有後繼節點 並且
dn != d && // 在隊列中 並且
dp.casNext(d, dn))) // 將被清除的節點的前驅節點的後繼節點設置爲被清除的節點的後繼節點,也就是d.next = d.next.next;
/* 清理cleanMe節點 */
casCleanMe(dp, null);
if (dp == pred)
return; // s is already saved node
/* 將前驅節點標記爲cleanMe節點 */
} else if (casCleanMe(null, pred))
return; // Postpone cleaning s
}
}
分析:1. 如果是刪除頭節點的後繼節點,將該後繼節點設置爲頭節點
2. 如果是刪除中間節點,prev.next = prev.next.next;
3. 如果是刪除尾節點,標記爲cleanMe節點,等待它有新的後繼節點時才進行刪除
TransferStack
明天會補。。。