SynchronousQueue简介
-
SynchronousQueue:同步队列,当生产者线程提交请求到SynchronousQueue时要等到消费者线程取走,否则就需要自旋和阻塞
-
SynchronousQueue中的队列存储的不再是生产者线程生产的元素,可以理解为存储生产者线程和消费者线程
-
非公平模式下,请求结点只能和栈顶结点匹配,而栈是先进后出,不公平
-
公平模式下,请求结点只能和头结点匹配,我就不画了
/*
生产者请求:成功:返回生产的数据
失败:返回null
消费者请求:成功:返回拿到的生产者的数据
失败:返回null
什么情况下会失败? 请求在指定超时时间内未匹配成功就会返回null
*/
abstract static class Transferer {
/*
e == null: 当前请求为消费
e != null: 当前请求为生产
timed: 指定超时
nanos: 指定超时,但nanos <= 0就是不能阻塞
*/
abstract E transfer(E e, boolean timed, long nanos);
}
//CPU数量
static final int NCPUS = Runtime.getRuntime().availableProcessors();
//最大自旋次数
static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
//不指定超时限制时的最大自旋次数
static final int maxUntimedSpins = maxTimedSpins * 16;
//如果指定超时时间小于spinForTimeoutThreshold,就不会阻塞挂起
static final long spinForTimeoutThreshold = 1000L;
非公平模式
-
非公平模式采用栈来保存请求结点,当请求到来时,如果栈顶结点可以匹配,那么当前请求入栈两者进行匹配,匹配成功一起出栈
-
当请求到来时,如果栈顶和自己相同,那么入栈等待匹配
-
当请求到来时,如果栈顶是正在匹配状态,帮助其匹配出栈
//非公平模式:栈
static final class TransferStack extends Transferer {
//当前结点请求是消费
static final int REQUEST = 0;
//当前结点请求是生产
static final int DATA = 1;
//当前结点请求正在匹配
/*
举例:当前栈顶为REQUEST,此时DATA请求到来,这个请求入栈的结点状态为 FULFILLING|DATA = 3
isFulfilling(3) = 2: 这个结点正在匹配
*/
static final int FULFILLING = 2;
//判断当前结点是否正在匹配
static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
static final class SNode {
//下一个结点
volatile SNode next;
//与当前结点匹配的结点
volatile SNode match;
//当前结点在自旋次数内未匹配成功,线程阻塞前waiter会保存线程引用,匹配成功后再唤醒
volatile Thread waiter; // to control park/unpark
Object item; // data; or null for REQUESTs
//当前结点的模式:DATA/REQUEST/FULFILLING
int mode;
// Note: item and mode fields don't need to be volatile
// since they are always written before, and read after,
// other volatile/atomic operations.
SNode(Object item) {
this.item = item;
}
//CAS方式设置结点的next字段
boolean casNext(SNode cmp, SNode val) {
return cmp == next &&
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
//进行tryMatch()操作的是:栈顶的下一个节点,就是和栈顶匹配的结点
boolean tryMatch(SNode s) {
//match == null:当前结点尚未匹配
//CAS方式设置结点的match字段:匹配
if (match == null &&
UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
//线程挂起前,会保存到waiter中
Thread w = waiter;
//线程已经挂起
if (w != null) { // waiters need at most one unpark
waiter = null;
//唤醒
LockSupport.unpark(w);
}
return true;
}
return match == s;
}
//取消结点:把match字段设置为自己
void tryCancel() {
UNSAFE.compareAndSwapObject(this, matchOffset, null, this);
}
//match字段是结点自己:该结点已经取消
boolean isCancelled() {
return match == this;
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long matchOffset;
private static final long nextOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class k = SNode.class;
matchOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("match"));
nextOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("next"));
} catch (Exception e) {
throw new Error(e);
}
}
}
//栈顶指针
volatile SNode head;
//设置栈顶元素
boolean casHead(SNode h, SNode nh) {
return h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh);
}
static SNode snode(SNode s, Object e, SNode next, int mode) {
if (s == null) s = new SNode(e);
s.mode = mode;
s.next = next;
return s;
}
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
//包装当前线程的结点
SNode s = null; // constructed/reused as needed
//e == null:当前线程请求是REQUEST,消费数据
//e != null:当前线程请求是DATA,生产数据
int mode = (e == null) ? REQUEST : DATA;
//自旋
for (;;) {
//栈顶指针
SNode h = head;
//情况一:栈为空 或 栈顶结点模式与当前请求模式一致
if (h == null || h.mode == mode) { // empty or same-mode
//当前线程请求不支持阻塞
if (timed && nanos <= 0) {
//栈顶已经取消,清理出栈
if (h != null && h.isCancelled())
casHead(h, h.next); // pop cancelled node
else
return null;
}
//先入栈,等待匹配
else if (casHead(h, s = snode(s, e, h, mode))) {
//当前请求入栈成功
//awaitFulfill():等待被匹配,具体后面会写
//1.正常情况:返回匹配的节点
//2.取消情况:返回当前节点
SNode m = awaitFulfill(s, timed, nanos);
//取消情况
if (m == s) { // wait was cancelled
//取消的结点出栈
clean(s);
return null;
}
//正常情况
//匹配成功后还未出栈
if ((h = head) != null && h.next == s)
//出栈
casHead(h, s.next); // help s's fulfiller
//当前请求为REQUEST:返回匹配的结点的item
//当前请求为DATA:返回自己的item
return (E) ((mode == REQUEST) ? m.item : s.item);
}
}
//情况二:栈顶结点模式与当前请求模式不一致,且栈顶没有正在匹配,也就是当前请求可以和栈顶匹配
else if (!isFulfilling(h.mode)) { // try to fulfill
//栈顶已取消,清理出栈
if (h.isCancelled()) // already cancelled
casHead(h, h.next); // pop and retry
//先入栈,去匹配栈顶(入栈后该结点成为新的栈顶,新的栈顶和旧的栈顶匹配)
else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
//当前请求入栈成功
//自旋
for (;;) { // loop until matched or waiters disappear
//s为栈顶,栈顶和栈顶的next匹配
SNode m = s.next; // m is s's match
//m == null ?
//s.next超时或者中断后,把自己出栈了
if (m == null) { // all waiters are gone
//把栈顶清空,回到外层自旋重新判断
casHead(s, null); // pop fulfill node
s = null; // use new node next time
break; // restart main loop
}
//此时情况:s -> m -> mn
SNode mn = m.next;
//尝试匹配,匹配成功会唤醒m结点中保存的线程
if (m.tryMatch(s)) {
//匹配成功s 和 m 都出栈
casHead(s, mn); // pop both s and m
//当前请求为REQUEST:返回匹配的结点的item
//当前请求为DATA:返回自己的item
return (E) ((mode == REQUEST) ? m.item : s.item);
} else // lost match
//强制出栈
s.casNext(m, mn); // help unlink
}
}
}
//情况三:栈顶正在匹配,当前请求协助匹配
else { // help a fulfiller
//s为栈顶,栈顶和栈顶的next匹配
SNode m = h.next; // m is h's match
//m == null ?
//s.next超时或者中断后,把自己出栈了
if (m == null) // waiter is gone
//把正在匹配的结点出栈
casHead(h, null); // pop fulfilling node
else {
//此时情况:h -> m -> mn
SNode mn = m.next;
//尝试匹配
if (m.tryMatch(h)) // help match
//匹配成功h 和 m 都出栈
casHead(h, mn); // pop both h and m
else // lost match
//强制出栈
h.casNext(m, mn); // help unlink
}
}
}
}
//s结点会先自旋,在自旋次数内如果匹配成功就会返回,否则阻塞
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
//等待的截止时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
//shouldSpin():该结点是否应该自旋
//指定超时maxTimedSpins为32,否则为32*16
int spins = (shouldSpin(s) ? (timed ? maxTimedSpins : maxUntimedSpins) : 0);
//自旋
for (;;) {
//收到中断,取消结点
if (w.isInterrupted())
s.tryCancel();
//m:与当前结点匹配的结点
//1.正常情况:匹配的节点
//2.取消情况:当前结点
SNode m = s.match;
if (m != null)
//可能正常,也可能是取消
return m;
//指定了超时限制
if (timed) {
//nanos: 距离超时还有多久
nanos = deadline - System.nanoTime();
if (nanos <= 0L) {
//已经超时了,取消结点
s.tryCancel();
continue;
}
}
//情况一:还可以继续自旋
if (spins > 0)
//自旋次数减一
spins = shouldSpin(s) ? (spins-1) : 0;
//情况二:spins == 0,自旋次数已到
else if (s.waiter == null)
//当前线程保存到当前结点waiter中
s.waiter = w; // establish waiter so can park next iter
//情况三:未指定超时
else if (!timed)
//挂起当前线程
LockSupport.park(this);
//情况四:指定了超时,且大于1000纳秒
else if (nanos > spinForTimeoutThreshold)
//挂起当前线程
LockSupport.parkNanos(this, nanos);
}
}
//当前线程是否该自旋
boolean shouldSpin(SNode s) {
SNode h = head;
// h == s: 当前结点为栈顶
//h == null: 当前结点已出栈,匹配成功后会被出栈
//isFulfilling(h.mode): 当前结点不是栈顶,但正在匹配
return (h == s || h == null || isFulfilling(h.mode));
}
//将s出栈
void clean(SNode s) {
s.item = null; // forget item
s.waiter = null; // forget thread
SNode past = s.next;
//找到s结点活跃的后继
if (past != null && past.isCancelled())
past = past.next;
// Absorb cancelled nodes at head
SNode p;
//如果栈顶是取消结点,就清理出栈,直到栈顶为正常结点或者到达past
//在此期间,可能会把s清理出栈
while ((p = head) != null && p != past && p.isCancelled())
casHead(p, p.next);
//从栈顶向下寻找取消结点,清理出栈,直到past
//如果s还在栈中,s一定会被清理出栈
while (p != null && p != past) {
//获取p.next
SNode n = p.next;
if (n != null && n.isCancelled())
p.casNext(n, n.next);
else
p = n;
}
}
// Unsafe mechanics
private static final sun.misc.Unsafe UNSAFE;
private static final long headOffset;
static {
try {
UNSAFE = sun.misc.Unsafe.getUnsafe();
Class k = TransferStack.class;
headOffset = UNSAFE.objectFieldOffset
(k.getDeclaredField("head"));
} catch (Exception e) {
throw new Error(e);
}
}
}
公平模式
-
公平模式采用队列来保存请求结点,当请求到来时,如果头结点可以匹配,进行匹配,匹配成功唤醒头结点线程返回结果
-
当请求到来时,如果尾结点和自己相同,那么入队等待匹配
//公平模式队列
static final class TransferQueue extends Transferer {
/** Node class for TransferQueue. */
static final class QNode {
//下一个结点
volatile QNode next; // next node in queue
volatile Object item; // CAS'ed to or from null
//当前结点在自旋时间内未匹配成功,线程阻塞前waiter会保存线程引用,匹配成功后再唤醒
volatile Thread waiter; // to control park/unpark
//true:当前请求是生产 false:当前请求是消费
final boolean isData;
QNode(Object item, boolean isData) {
this.item = item;
this.isData = isData;
}
//CAS方式设置结点的next字段
boolean casNext(QNode cmp, QNode val) {
return next == cmp &&
UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
}
//CAS方式设置结点的item字段
boolean casItem(Object cmp, Object val) {
return item == cmp &&
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, val);
}
//取消结点:把item字段设置为自己
void tryCancel(Object cmp) {
UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
}
//item字段是结点自己:该结点已经取消
boolean isCancelled() {
return item == this;
}
//当next指向自己,表明当前结点已经不再队列内
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);
}
}
}
//头指针
transient volatile QNode head;
//尾指针
transient volatile QNode tail;
/**
* Reference to a cancelled node that might not yet have been
* unlinked from queue because it was the last inserted node
* when it was cancelled.
*/
//还未从队列中出队的取消结点,因为当它取消的时候刚插入,此时可能有其它结点插入到他后面了
transient volatile QNode cleanMe;
TransferQueue() {
QNode h = new QNode(null, false); // initialize to dummy node.
head = h;
tail = h;
}
//设置新的头指针,相当于头结点出队
void advanceHead(QNode h, QNode nh) {
if (h == head &&
UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
h.next = h; // forget old next
}
//设置新的尾指针,将结点入队
void advanceTail(QNode t, QNode nt) {
if (tail == t)
UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
}
//CAS方式设置cleanMe
boolean casCleanMe(QNode cmp, QNode val) {
return cleanMe == cmp &&
UNSAFE.compareAndSwapObject(this, cleanMeOffset, cmp, val);
}
/**
* Puts or takes an item.
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {
//包装当前线程的结点
QNode s = null; // constructed/reused as needed
//isData == true:生产
//isData == false:消费
boolean isData = (e != null);
//自旋
for (;;) {
QNode t = tail;
QNode h = head;
if (t == null || h == null) // saw uninitialized value
continue; // spin
//情况一:队列为空 或 队尾结点和当前结点请求模式一致
if (h == t || t.isData == isData) { // empty or same-mode
QNode tn = t.next;
/*
入队过程:第一步:设置 tail.next = 自己
第二步:设置 自己 = tail
*/
//尾指针已经被其它线程更改,回到自旋
if (t != tail) // inconsistent read
continue;
//其它线程入队,已完成了第一步,第二步可能尚未完成
if (tn != null) { // lagging tail
//协助更新尾指针,回到自旋
advanceTail(t, tn);
continue;
}
//不支持阻塞
if (timed && nanos <= 0) // can't wait
return null;
if (s == null)
//为当前请求创建结点
s = new QNode(e, isData);
if (!t.casNext(null, s)) // failed to link in
//入队第一步失败,回到自旋
continue;
//入队第二步
advanceTail(t, s); // swing tail and wait
//awaitFulfill():等待被匹配,具体后面会写
//1.生产请求: 返回 this,当前请求对应结点取消了; 返回null:当前请求匹配成功,消费者拿走了item
//2.取消请求: 返回 this,当前请求对应结点取消了; 返回item:当前请求匹配成功,拿到了生产者的item
Object x = awaitFulfill(s, e, timed, nanos);
//结点取消,清理出队,并不是真正清理,用cleanMe保存了t,等待别的线程clean()再根据情况清除
if (x == s) { // wait was cancelled
clean(t, s);
return null;
}
//匹配成功
//尚未出队
if (!s.isOffList()) { // not already unlinked
//更新头指针
advanceHead(t, s); // unlink if head
//x != null:消费请求拿到了生产者的item
if (x != null) // and forget fields
s.item = s;
//已经出队,更新waiter
s.waiter = null;
}
//x != null: 消费者请求拿到了生产者的item,返回拿到的item
//x == null: 生产者的item被拿走了,返回自己的item
return (x != null) ? (E)x : e;
}
//情况二:队尾和自己不同,可以匹配
else { // complementary-mode
//h.next是真正的头结点
QNode m = h.next; // node to fulfill
//t != tail: 其它线程入队,修改了tail,回去重新自旋
//m == null || h!= head: 其他线程匹配了head.next,会更新头指针
if (t != tail || m == null || h != head)
continue; // inconsistent read
//头结点的item
Object x = m.item;
/*
isData == (x != null)成立: 1.当前结点为生产者请求,isData = true,此时头结点为消费者请求,但已经取消了x != null
2.当前结点为消费者请求,isData = false,此时头结点为生产者请求,但已经被匹配x == null
x == m:头结点已经取消
m.casItem(x, e):如果m为生产者请求 x == 生产的数据,当前消费者请求e == null,把生产者请求的item设置为null
如果m为消费者请求 x == null,当前生产者者请求e == 生产的数据,把消费者请求的item设置为生产的数据
*/
if (isData == (x != null) || // m already fulfilled
x == m || // m cancelled
!m.casItem(x, e)) { // lost CAS
//此次匹配失败,更新头指针继续匹配
advanceHead(h, m); // dequeue and retry
continue;
}
//匹配成功
//更新头指针,唤醒匹配结点的线程
advanceHead(h, m); // successfully fulfilled
LockSupport.unpark(m.waiter);
//x != null: 消费者请求拿到了生产者的item,返回拿到的item
//x == null: 生产者的item被拿走了,返回自己的item
return (x != null) ? (E)x : e;
}
}
}
//s结点会先自旋,在自旋次数内如果匹配成功就会返回,否则阻塞
Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
//等待的截止时间
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Thread w = Thread.currentThread();
//只有头结点允许自旋,因为只有头结点才可以匹配(head.next是真正的头结点)
int spins = ((head.next == s) ?
(timed ? maxTimedSpins : maxUntimedSpins) : 0);
//自旋
for (;;) {
//收到中断,取消结点
if (w.isInterrupted())
s.tryCancel(e);
Object x = s.item;
//此时item?
/*
生产者请求:
1.item == this 请求已取消
2.item == null 请求匹配成功,消费者拿走了item
3.item 是生产者要提交的数据
消费者请求:
1.item == this 请求已取消
2.item == null 请求正在匹配
3.item == 生产者的item 请求匹配成功
*/
if (x != e)
//item被改变,要么匹配成功了,要么取消请求
return x;
//指定了超时限制
if (timed) {
//nanos: 距离超时还有多久
nanos = deadline - System.nanoTime();
//已经超时,取消请求
if (nanos <= 0L) {
s.tryCancel(e);
continue;
}
}
//情况一:还可以继续自旋
if (spins > 0)
--spins;
//情况二:spins == 0,自选次数已到
else if (s.waiter == null)
//当前线程保存到当前结点waiter中
s.waiter = w;
//情况三:未指定超时,挂起当前线程
else if (!timed)
LockSupport.park(this);
//情况四:指定了超时,且大于1000纳秒,挂起当前线程
else if (nanos > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanos);
}
}
//真正清理的是之前的取消结点
void clean(QNode pred, QNode s) {
s.waiter = null; // forget thread
while (pred.next == s) { // Return early if already unlinked
QNode h = head;
QNode hn = h.next; // Absorb cancelled first node as head
//从头指针向后清理取消结点
if (hn != null && hn.isCancelled()) {
advanceHead(h, hn);
continue;
}
QNode t = tail; // Ensure consistent read for tail
//队列已经为空
if (t == h)
return;
QNode tn = t.next;
//其它线程入队更改了tail
if (t != tail)
continue;
//其它线程入队更改了tail.next,完成了入队第一步
if (tn != null) {
//协助更新尾指针
advanceTail(t, tn);
continue;
}
//此时要清理的s已经不是尾结点,就不去设置cleanMe了,直接在这出队
if (s != t) { // If not tail, try to unsplice
QNode sn = s.next;
//s结点取消就返回,否则把s出队
if (sn == s || pred.casNext(s, sn))
return;
}
/*
要清理的结点s是尾结点,到这设置cleanMe为pred
其它线程clean():有可能清除上次调用clean()的取消的结点
*/
QNode dp = cleanMe;
//上次清理设置了cleanMe
if (dp != null) { // Try unlinking previous cancelled node
//清理上次的取消的结点d
QNode d = dp.next;
QNode dn;
//d被清理了
if (d == null || // d is gone or
//d还队列中
d == dp || // d is off list or
//d未取消
!d.isCancelled() || // d not cancelled or
//d不是尾结点了,且d.next没有取消
(d != t && // d not tail and
(dn = d.next) != null && // has successor
dn != d && // that is on list
dp.casNext(d, dn))) // d unspliced
//设置cleanMe为null,上次未清理的取消结点已经被清理了或者上面的其它状况
casCleanMe(dp, null);
if (dp == pred)
return; // s is already saved node
//设置cleanMe为pred
} else if (casCleanMe(null, pred))
return; // Postpone cleaning s
}
}
}