上篇文章中,画图解释了,SynchronousQueue 的工作原理。
这篇文章,详细的解析源码(图解 SynchronousQueue原理)。
默认你已经读了上篇文章,这篇文章重点说源码。以公平模式为例
一、初始化
SynchronousQueue<Integer> queue = new SynchronousQueue<>(true);
public SynchronousQueue(boolean fair) {
transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}
TransferQueue() {
QNode h = new QNode(null, false); // initialize to dummy node.
head = h;
tail = h;
}
公平模式,底层是队列来实现的,看下这个内部类 TransferQueue
,有这四个属性
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;
初始化之后,大概就像下面这张图
二、调用 put() 会阻塞
用上篇文章中的例子, t1, t2, t3 先后往队列中放 10, 20, 30。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
if (transferer.transfer(e, false, 0) == null) {
Thread.interrupted();
throw new InterruptedException();
}
}
也就是说 put(e)
方法,会调用 transferer.transfer(e, false, 0)
。
多说一句,取元素与放元素都会调用这个 transfer
方法,只是参数不同而已。
这是三个线程操作之后 QNode 队列,结合图,来说源码。
E transfer(E e, boolean timed, long nanos) {
QNode s = null; // constructed/reused as needed
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;
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