SynchronousQueue源码阅读

174 阅读9分钟

SynchronousQueue简介

  • SynchronousQueue:同步队列,当生产者线程提交请求到SynchronousQueue时要等到消费者线程取走,否则就需要自旋和阻塞

  • SynchronousQueue中的队列存储的不再是生产者线程生产的元素,可以理解为存储生产者线程和消费者线程

Markdown

  • 非公平模式下,请求结点只能和栈顶结点匹配,而栈是先进后出,不公平

  • 公平模式下,请求结点只能和头结点匹配,我就不画了

		
	/*
		生产者请求:成功:返回生产的数据
				   失败:返回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
            }
        }
    }