并发编程 - 阻塞队列 - SynchronousQueue (公平模式)

前言

一种阻塞队列,插入操作必须要有对应的删除操作正在执行,反之亦然。它没有任何容量。不能执行peek()操作。不能迭代。适用于线程间的传递,一个线程向另一个线程传递一些信息、事件、或者任务等。支持公平(FIFO)和非公平模式(LIFO),默认是非公平。

(源自对SynchronousQueue官方注释的解读)

源码分析

构造器:

并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第1张图片

常用方法

  1. put(…)
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第2张图片

  2. offer(…)并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第3张图片

  3. take(…)
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第4张图片

  4. poll(…)并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第5张图片

  5. drainTo(…)
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第6张图片

  6. drainTo(…, …)
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第7张图片

TransferQueue

  1. 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);
                }
            }
        }
  1. 成员属性
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第8张图片

并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第9张图片

  1. 构造器
    在这里插入图片描述

  2. 设置头节点,并取消链接
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第10张图片

  3. 设置尾节点
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第11张图片

  4. 设置cleanMe节点
    并发编程 - 阻塞队列 - SynchronousQueue (公平模式)_第12张图片

  5. 传递(插入或者获取)元素

        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;
                }
            }
        }
  1. 自旋或者阻塞,直到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;

  1. 清理节点
        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

明天会补。。。

你可能感兴趣的:(多线程)