[JUC source code] blocking queue: SynchronousQueue source code analysis (fair mode)

Blocking queue series:

In the previous article, we talked about the unfair thread control logic of TransferStack based on the stack (FILO). In this article, we will look at the fair thread control logic of TransferQueue based on the queue (FIFO).

Let’s review a question first. How does the current thread pass its own data to the blocked thread?

For the convenience of explanation, we assume that thread 1 takes data into the queue and is blocked and becomes blocked thread A, and then thread 2 starts to put data B into the queue. The general flow is as follows:

  1. Thread 1 takes data from the queue and finds that there is no data in the queue, so it is blocked and becomes A;
  2. Thread 2 puts data to the end of the queue and finds the first blocked node from the end of the queue . Assuming that node A can be found at this time, then thread B puts the put data into the item attribute of node A. And wake up thread 1;
  3. After thread 1 is awakened, the data of thread 2 put can be obtained from A.item, and thread 1 returns successfully.

From this process, we can see that fairness is mainly reflected in the fact that every time data is put, it is put to the end of the team, and every time data is taken, the data is not directly taken from the head of the team, but from the end of the team. Look for the first blocked thread, so that the blocked threads will be released in order.

PS: The thread matching of TransferStack is based on the matching of the stack close to the top of the stack, so it is not fair.

TransferQueue (Fair=>FIFO)

static final class TransferQueue<E> extends Transferer<E>{
    
    
    // 队列头 
    transient volatile QNode head;
    // 队列尾 
    transient volatile QNode tail;

    // 队列的元素
    static final class QNode {
    
    ...}
    
    //...
}

QNode

static final class QNode {
    
    

	// 当前元素的值,如果当前元素被阻塞住了,等其他线程来唤醒自己时,其他线程会把自己 set 到 item 里面
    volatile Object item;         // CAS'ed to or from null
    // 可以阻塞住的当前线程
    volatile Thread waiter;       // to control park/unpark
     // true 是 put,false 是 take
    final boolean isData;
    
    // 当前元素的下一个元素
    volatile QNode next;         
	
	// 构造时传入数据和节点类型
	QNode(Object item, boolean isData) {
    
    
	    this.item = item;
	    this.isData = isData;
	}
	
	// 将节点val通过cas连接在cmp后面
	boolean casNext(QNode cmp, QNode val) {
    
    
	    return next == cmp &&
	        UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
	}
	
	// 将item的值通过cas变为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);
	}
	
	// 被取消的节点就是item=this
	boolean isCancelled() {
    
    
	    return item == this;
	}
	
	// unsafe相关代码...
} 

transfer(): Enqueue & Dequeue

E transfer(E e, boolean timed, long nanos) {
    
    

    QNode s = null; // constructed/reused as needed
    // true 是 put,false 是 get
    boolean isData = (e != null);

    for (;;) {
    
    
        // 队列头和尾的临时变量,队列是空的时候,t=h
        QNode t = tail;
        QNode h = head;
        // tail 和 head 没有初始化时,无限循环
        // 虽然这种continue非常耗cpu,但一般碰不到这种情况,因为tail和head 在 TransferQueue 初始化时就已经被赋值空节点了
        if (t == null || h == null)
            continue;
-----------------------------------------------------------------------------------------------------------------                        
        // 情况一:首尾节点相同(空队列)|| 尾节点的操作和当前节点操作一致(比如队尾是take时阻塞,当前线程也是take)
        if (h == t || t.isData == isData) {
    
    
            QNode tn = t.next;
            // 当 t 不是 tail 时。即 tail 已经被修改过了,因为 tail 没有被修改的情况下,t 和 tail 必然相等
            if (t != tail)
                continue;
            // 队尾后面的值还不为空,t 还不是队尾,直接把 tn 赋值给 t,这是一步加强校验。
            if (tn != null) {
    
    
            	// CAS修改tail为tn
                advanceTail(t, tn);
                continue;
            }
            // 超时直接返回 null
            if (timed && nanos <= 0)        // can't wait
                return null;
            // 构造node节点
            if (s == null)
                s = new QNode(e, isData);
            // 如果把 e 放到队尾失败,继续递归放进去
            if (!t.casNext(null, s))        // failed to link in
                continue;

            advanceTail(t, s);              // swing tail and wait
            // awaitFulfill 同 TransferStack,阻塞住自己,等待配对节点x
            Object x = awaitFulfill(s, e, timed, nanos);
            if (x == s) {
    
                       // wait was cancelled
                clean(t, s);
                return null;
            }

            if (!s.isOffList()) {
    
       // not already unlinked
            	// CAS修改head为s     
                advanceHead(t, s);  // unlink if head
                if (x != null)      // and forget fields
                    s.item = s;
                s.waiter = null;
            }
            return (x != null) ? (E)x : e;
-----------------------------------------------------------------------------------------------------------------            
        // 情况二:队列不为空,并且当前操作和队尾不一致(比如队尾是因为 take 被阻塞的,那么当前操作必然是 put)
        } else {
    
                                // complementary-mode
            // 如果是第一次执行,此处的 m 代表就是 tail
            // 也就是这行代码体现出队列的公平,每次操作时,从头开始按照顺序进行操作
            QNode m = h.next;               // node to fulfill
            if (t != tail || m == null || h != head)
                continue;                   // inconsistent read

            Object x = m.item;
            if (isData == (x != null) ||    // m already fulfilled
                x == m ||                   // m cancelled
                // m 代表栈头
                // 这里把当前的操作值赋值给阻塞住的 m 的 item 属性,所以 m 被释放时,就可得到此次操作的值
                !m.casItem(x, e)) {
    
             // lost CAS
                advanceHead(h, m);          // dequeue and retry
                continue;
            }
            // 当前操作放到队头
            advanceHead(h, m);              // successfully fulfilled
            // 释放队头阻塞节点
            LockSupport.unpark(m.waiter);
            return (x != null) ? (E)x : e;
        }
    }
}

Guess you like

Origin blog.csdn.net/weixin_43935927/article/details/113964294