并发容器学习—SynchronousQueue

一、SynchronousQueue并发容器
1.Synchronous Queue的底层实现
    Synchronous Queue称为同步队列,是一种 容量为0的阻塞队列。每个插入操作必须等待另一个线程的对应移除操作 ,反之亦然。也就是说同步队列面向的是操作,而不是数据元素,即同步队列是入队操作而不是入队数据,这个操作可以是take或者put,put操作与take操作相对应。再简单点说,同步队列可以看做是一个只有入队没有出队的面向操作的队列,没执行一次take或put,本质上都是在执行一次操作的入队;只是在队列的内部执行时,会根据每次入队的操作类型进行匹配,每配对成功一对take和put操作,就会将这两个操作从队列中移除并反馈给对应的调用线程。
public SynchronousQueue() {
    this(false);
}

public SynchronousQueue(boolean fair) {
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

    上面是SynchronousQueue的两个构造方法,可以看出SynchronousQueue的底层实际是创建一个转移队列,并且这个队列有公平和非公平两种模式,下面我们先来看看公平模式的转移队列是怎么实现的。

 

2.SynchronousQueue的公平模式

    不论是非公平的TransferStack队列还是公平的TransferQueue队列,都是对父类Transfer的实现:

//Transferer是SynchronousQueue中的一个内部类,定义了一个转移方法
//TransferStack和TransferQueue都要实现该转移方法
abstract static class Transferer<E> {
    abstract E transfer(E e, boolean timed, long nanos);
}

    TransferQueue的是一个底层由链表实现的FIFO队列,其结点的定义如下:

static final class QNode {
    volatile QNode next;          // 结点的后继
    volatile Object item;         // 结点中存储的数据
    volatile Thread waiter;       // 等待的线程

    //是否是数据,此标识要与判断入队的操作是什么操作
    //即判断相邻两次入队的操作是否相同,若是相邻两次入队
    //的是不相同的操作(一次put一次take)那么就要进行配对后移除出队。
    //否则,将操作入队即可
    final boolean isData;    

    //构造方法
    QNode(Object item, boolean isData) {
        this.item = item;
        this.isData = isData;
    }

    //CAS更新后继结点
    boolean casNext(QNode cmp, QNode val) {
        return next == cmp &&
            UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
    }

    //CAS更新结点中的数据
    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;
    }

    //判断当前结点是否已不再队列之中
    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);
        }
    }
}

    知道了TransferQueue的底层实现,在看看TransferQueue中重要的属性及构造方法:

static final class TransferQueue<E> extends Transferer<E> {

    //队列的队首结点
    transient volatile QNode head;
    //队列的队尾结点
    transient volatile QNode tail;
    //清除标记
    transient volatile QNode cleanMe;

    TransferQueue() {
        QNode h = new QNode(null, false); // initialize to dummy node.
        head = h;
        tail = h;
    }

    private static final sun.misc.Unsafe UNSAFE;
    private static final long headOffset;
    private static final long tailOffset;
    private static final long cleanMeOffset;
    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = TransferQueue.class;
            headOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("head"));
            tailOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("tail"));
            cleanMeOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("cleanMe"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }
}

3.公平模式下的take和put操作

//将指定元素添加到此队列,如有必要则等待另一个线程接收它
public void put(E e) throws InterruptedException {
    //判断转移元素是否为null,也就是说同步队列中不能对null元素进行转移
    //因为e元素是否为null,是transfer方法中判断入队操作是put还是take
    //的一个依据
    if (e == null) throw new NullPointerException();

    //put方法中传入transfer的e不为null
    //调用transfer 默认不进行超时等待,如果发生中断则抛出中断异常
    if (transferer.transfer(e, false, 0) == null) {
        Thread.interrupted();
        throw new InterruptedException();
    }
}

//获取并移除此队列的头,如有必要则等待另一个线程插入它
public E take() throws InterruptedException {

    //take方法中传入transfer方法的e为null
    E e = transferer.transfer(null, false, 0);
    if (e != null)
        return e;
    Thread.interrupted();
    throw new InterruptedException();
}

 

    由take方法和put方法的源码可知,在公平模式下,这两个方法本质都是对TransferQueue中transfer方法的调用,下面来看看TransferQueue中的transfer方法是如何实现的?

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

    QNode s = null; 

    //根据e是否为null,标记本次入队的是什么操作
    //e为null,isData为false,否则isData为true
    boolean isData = (e != null);


    for (;;) {    //自旋
        QNode t = tail;    //获取队尾
        QNode h = head;    //获取队首

        //判断队首或队尾是否为null,实际上h和t不会为null(构造方法中已经初始化过)
        if (t == null || h == null)         // saw uninitialized value
            continue;                       // spin

        //判断是否是空队列,或者入队操作与队尾相同(即与队尾都是put或者take操作)
        //不论是空队列还是与队尾相同操作,说明只能将操作入队,而不能进行
        //匹配(操作相同,无法配对,配对要操作不同才行)
        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;
            }

            //判断是否超时(timed为是否设置了超时等待操作,nanos为剩余的等待时间)
            if (timed && nanos <= 0)        // can't wait
                return null;    //超时后直接返回null

            //判断s是否为null,若是则以e为item创建一个结点
            if (s == null)
                s = new QNode(e, isData);
            
            //尝试更新队尾的后继结点为s结点,失败的话就循环继续尝试直到成功
            if (!t.casNext(null, s))        // failed to link in
                continue;

            //在队尾新增了一个后继结点,那么队尾就应该是这个后继结点了
            //因此需要将s更新为新的队尾结点
            advanceTail(t, s);              // swing tail and wait

            //空旋或者阻塞直到匹配的操作到来
            Object x = awaitFulfill(s, e, timed, nanos);

            //到这一步,说明阻塞的操作已经配对成功或者操作已经被取消了,线程被唤醒了
            //判断是配对成功了,还是操作被取消了
            //若是操作被取消,会设置s.item=s
            if (x == s) {                   // wait was cancelled
                clean(t, s);    //清除结点s
                return null;    //操作已经被取消,直接返回null
            }

            //判断结点s是否还在队列中
            //若是还在队列中,且又配对操作成功,说明s结点应该是新的head
            //并且若s.item不为null还需要将s.item设为s自身,等待线程赋null
            if (!s.isOffList()) {           // not already unlinked
                advanceHead(t, s);          // unlink if head
                //判断是否
                if (x != null)              
                    s.item = s;
                s.waiter = null;
            }
            return (x != null) ? (E)x : e;

        // 入队的操作与之前的队尾的操作不同,可以进行配对(take配put,或
        // put配take)
        } else {    
            //获取队首的后继结点
            QNode m = h.next;               
            
            //出现t与队尾不同,m为null,h与队首不同,说明队列发生了改变
            //即队列出现了其他线程抢先执行了入队或者配对的操作
            if (t != tail || m == null || h != head)
                continue;    //循环重新来

            //获取后继结点的item
            Object x = m.item;

            //isData == (x != null)是判断m结点对应的操作与当前操作是否相同
            //x == m 则是判断m结点是否被取消
            //!m.casItem(x, e) 则是判断尝试更新m结点的item为e是否成功
            //以上三个判断有一个为真,那就说明m结点已经不在队列中或是被取消或是匹配过了
            if (isData == (x != null) || x == m || !m.casItem(x, e)) {         
                advanceHead(h, m);          //旧队首已经过时,更新队首
                continue;
            }

            //更新head,到此处说明配对操作已经成功,应该将m结点变为head
            //而h结点则需要移除出列
            advanceHead(h, m);              // successfully fulfilled
            LockSupport.unpark(m.waiter);    //唤醒m结点对应的线程

            //
            return (x != null) ? (E)x : e;
        }
    }
}

//尝试更新队尾结点
void advanceTail(QNode t, QNode nt) {
    if (tail == t)
        UNSAFE.compareAndSwapObject(this, tailOffset, t, nt);
}

//等待结点被对应的操作匹配
Object awaitFulfill(QNode s, E e, boolean timed, long nanos) {
    //根据timed标识即超时时间计算截止时间
    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;    //获取结点对应的item对象

        //判断结点的item是否还是对象e
        //生成s节点的时候,s.item是等于e的,当取消操作(item变为s)或者
        //匹配了操作的时候会进行更改
        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);
    }
}

//尝试取消当前结点对应的操作,即将结点中item值更新成结点自身(this)
void tryCancel(Object cmp) {
    UNSAFE.compareAndSwapObject(this, itemOffset, cmp, this);
}

//更新队首head指针,并将原队首结点的next指向其自身,方便GC
void advanceHead(QNode h, QNode nh) {
    if (h == head &&
        UNSAFE.compareAndSwapObject(this, headOffset, h, nh))
        h.next = h; // forget old next
}


//若是某个结点对应的操作被取消,那么这个操作对应的结点需要移除出队
//也就是清理无效结点。
/**
* clean方法中如果删除的节点不是尾节点,那么可以直接进行删除,
* 如果删除的节点是尾节点,那么用cleanMe标记需要删除的节点的前驱,
* 这样在下一轮的clean的过程将会清除打了标记的节点。
*/
void clean(QNode pred, QNode s) {
    s.waiter = null;     //操作已经被取消,那么就不会有等待线程了

    //判断s是否是pred的后继结点
    while (pred.next == s) { // Return early if already unlinked
        QNode h = head;    //队首引用
        QNode hn = h.next;   //队首的后继结点

        //判断hn是否被取消,若被取消,那么更新head
        if (hn != null && hn.isCancelled()) {
            advanceHead(h, hn);
            continue;
        }
        QNode t = tail;      // 队尾结点

        //判断是否是空队列
        if (t == h)
            return;
        QNode tn = t.next;    //队尾的后继

        //队尾改变,说明队列被其他线程修改过了
        if (t != tail)
            continue;

        //t有后继结点,说明队尾该更新了
        if (tn != null) {
            advanceTail(t, tn);
            continue;
        }

        //判断s结点是否是队尾结点
        //若不是队尾结点,则只需将s的前驱pred结点的next指向s结点的后继结点sn
        //即成功将s结点从队列中清除
        if (s != t) {        // If not tail, try to unsplice
            QNode sn = s.next;
            if (sn == s || pred.casNext(s, sn))
                return;
        }

        //到此处,说明要清除的结点就是队列的队尾,而队尾不能直接删除
        QNode dp = cleanMe;    //获取标识有要删除的结点的前驱结点

        //判断是否有需要删除的结点,dp不为null,即cleanMe存在
        //说明队列之前有队尾结点需要删除
        if (dp != null) {    // Try unlinking previous cancelled node
            QNode d = dp.next;
            QNode dn;

            //当cleanMe处于以下四种情形时,cleanMe失效
            //(1)cleanMe的后继而空(cleanMe 标记的是需要删除节点的前驱)
            //(2)cleanMe的后继等于自身,
            //(3)需要删除节点的操作没有被取消,
            //(4)被删除的节点不是尾节点且其后继节点有效
            if (d == null ||               // d is gone or
                d == dp ||                 // d is off list or
                !d.isCancelled() ||        // d not cancelled or
                (d != t &&                 // d not tail and
                 (dn = d.next) != null &&  //   has successor
                 dn != d &&                //   that is on list
                 dp.casNext(d, dn)))       // d unspliced
                casCleanMe(dp, null);    //cleanMe失效,赋值为null
            if (dp == pred)
                return;      // s is already saved node
        } else if (casCleanMe(null, pred))    //将队尾的前驱结点标记成cleanMe
            return;          // Postpone cleaning s
    }
}

//用于判断结点是否还在队列中,若后继结点是自身,说明已经不再队列中
//否则还在队列中
boolean isOffList() {
    return next == this;
}

由上面对公平的SynchronousQueue的分析可知,底层是使用队列来实现公平模式的,并且线程安全是通过CAS方式实现的。公平的TransferQueue队列中会将连续相同的操作入队,而不同的操作则会进行配对,即TransferQueue队列中要么没有存放操作,要么存放都是相同的操作(要么都是take,要么都是put),当有一个与队列中的操作不相同的操作时,队列会自动将队首操作与之进行匹配。大致流程(操作被取消未显示,方便理解)如下图所示:

b5a109741c2effb8a1f9eba8b957151be07.jpg

4.SynchronousQueue的非公平模式

    SynchronousQueue的非公平模式是基于栈来实现的,我们知道栈是后进先出的(LIFO),也就是说这里的非公平模式与ReentrantLock中的非公平模式区别巨大,后来先服务这太不公平了。

    先来看看非公平模式的具体实现TransferStack的底层数据结构链表中结点的定义:

static final class SNode {
    volatile SNode next;        // 链表的后继结点
    volatile SNode match;       // 匹配的结点
    volatile Thread waiter;     // 等待的线程
    Object item;                // 数据
    int mode;        //结点的模式

    SNode(Object item) {
        this.item = item;
    }

    //CAS方式更新后继结点
    boolean casNext(SNode cmp, SNode val) {
        return cmp == next &&
            UNSAFE.compareAndSwapObject(this, nextOffset, cmp, val);
    }

    //尝试匹配结点,匹配成功就将等待匹配结点对应的线程唤醒继续后续操作
    boolean tryMatch(SNode s) {
        if (match == null &&
            UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
            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);
    }

    //判断是否被取消
    boolean isCancelled() {
        return match == this;
    }


    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);
        }
    }
}

 

    知道了结点的基本结构,在来看看TransferStack中的重要属性及构造方法:

//TransferStack中没有构造方法,因此只有一个空构造
/**
* TransferStack中定义了三个标记:REQUEST表示消费者,DATA表示生产者,
* FULFILLING表示操作匹配状态。任何线程对TransferStack的操作都属于
* 上述3种状态中的一种
*/
static final class TransferStack<E> extends Transferer<E> {
    //用于标记结点的类型,代表结点是消费者(对应take操作)
    static final int REQUEST    = 0;
    //用于标记结点的类型,代表结点是生产者(对应put操作)
    static final int DATA       = 1;
    //用于标记结点的状态,代表结点正处于匹配状态
    static final int FULFILLING = 2;

    //栈顶结点
    volatile SNode head;

    // 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);
        }
    }
}

5.非公平模式下的take和put操作

    有上文对公平模式的学习,我们知道take和put操作最终调用的都是transfer方法,只不过公平模式调用的是TransferQueue中的转移方法,非公平模式则是调用TransferStack中的转移方法

/**
* transfer的大致过程:将一个操作与栈顶的操作进行配对
* 若是配对不成功(take对应put,或put对应take),那么直接将该操作
* 入栈;若是配对成功,即此时应该将栈顶操作出栈,但是不能直接出栈(
* 若此时其他线程进行入栈,那么直接出栈会出问题),而是先将匹配的操作
* 标记成FULFILLING状态(匹配状态)然后入栈;当其他线程检查到这个匹配
* 的过程,就会先帮助配对,在去执行自身的操作
*/
@SuppressWarnings("unchecked")
E transfer(E e, boolean timed, long nanos) {

    SNode s = null; // constructed/reused as needed

    //判断当前操作是何种模式,REQUEST对应take,DATA对应put
    int mode = (e == null) ? REQUEST : DATA;

    for (;;) {    //死循环
        SNode h = head;    //获取栈顶

        //判断栈是否为空栈,若不为空栈,那么栈顶操作模式与当前操作模式是否相同
        //若是栈顶操作与当前操作模式相同,那么就需要入栈该操作
        if (h == null || h.mode == mode) {  // empty or same-mode

            //判断是否设置了超时等待,若设置了超时等待,那等待时间是否还有剩余
            if (timed && nanos <= 0) {      

                //判断栈顶是否为null,且栈顶是否被取消
                //若不为null,且栈顶操作被取消,那么就尝试更新栈顶操作为其后继
                if (h != null && h.isCancelled())
                    casHead(h, h.next);     // pop cancelled node
                else    //栈顶为null或者没被取消
                    return null;

            //没有设置超时等待,或超时等待时间还未到,则尝试将当前操作入栈
            } else if (casHead(h, s = snode(s, e, h, mode))) {
                //s入栈成功,那么就自旋或挂起等待匹配的操作到来在被唤醒
                SNode m = awaitFulfill(s, timed, nanos);    //操作自旋或挂起

                //到这一步说明操作已经被取消,或者匹配到了对应的操作
                //匹配结点m为结点自己本身,说明操作被取消
                if (m == s) {               // wait was cancelled
                    clean(s);    //清除被取消的结点
                    return null;
                }
                //若是栈不是空栈且栈顶的后继是s,说明操作s和其匹配的操作m,都还在栈中
                //需要将其移除出栈,即更新栈顶为s的后继
                if ((h = head) != null && h.next == s)
                    casHead(h, s.next);     // help s's fulfiller

                //根据操作类型返回对应的数据,最后返回的其实都是put进去的数据
                return (E) ((mode == REQUEST) ? m.item : s.item);
            }

        //当前的操作与栈顶操作相匹配,进行匹配,将操作的状态更新成FULFILLING并入栈
        } else if (!isFulfilling(h.mode)) { // try to fulfill
            if (h.isCancelled())            // 判断栈顶是否被取消
                casHead(h, h.next);         // 栈顶被取消更新栈顶

            //入栈新结点s,s的后继为h,并且s处于FULFILLING状态(匹配状态)
            else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
                for (;;) { // loop until matched or waiters disappear
                    SNode m = s.next;       // s的后继m,因为s处于匹配状态,m可能是其配对的结点

                    //配对结点为null
                    //这里有些疑问,没搞懂什么情形下会出现m为null(按理不应该出现的)
                    if (m == null) {        // all waiters are gone
                        casHead(s, null);   // pop fulfill node
                        s = null;           // use new node next time
                        break;              // restart main loop
                    }

                    //m的后继结点
                    SNode mn = m.next;
                    //判断m和s配对是否成功,配对成功尝试更新栈顶为m的后继
                    if (m.tryMatch(s)) {
                        casHead(s, mn);     // pop both s and m
                        return (E) ((mode == REQUEST) ? m.item : s.item);
                    } else                  // lost match
                        //没有匹配成功,说明m结点不是s的配对结点,继续向后寻找
                        s.casNext(m, mn);   // help unlink
                }
            }

        //到这说明栈顶处于匹配状态,那么帮助其匹配
        } else {                            // help a fulfiller
            SNode m = h.next;               // m is h's match
            if (m == null)                  // waiter is gone
                casHead(h, null);           // pop fulfilling node
            else {
                SNode mn = m.next;
                if (m.tryMatch(h))          // help match
                    casHead(h, mn);         // pop both h and m
                else                        // lost match
                    h.casNext(m, mn);       // help unlink
            }
        }
    }
}

//将结点对应的线程自旋或挂起以等待匹配的操作到来
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
    //计算截止时间
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    Thread w = Thread.currentThread();

    //计算自旋时间
    int spins = (shouldSpin(s) ?
                 (timed ? maxTimedSpins : maxUntimedSpins) : 0);
    for (;;) {
        if (w.isInterrupted())
            s.tryCancel();    //尝试取消操作
        SNode m = s.match;    //获取匹配的结点

        //匹配结点不为null,说明要么匹配到了,要么被取消,都可以结束挂起了
        if (m != null)
            return m;

        //判断是否设置了超时等待
        if (timed) {
            //计算剩余时间
            nanos = deadline - System.nanoTime();
            //设置了超时等待,若截止时间已到,那么操作要被取消
            if (nanos <= 0L) {
                s.tryCancel();
                continue;
            }
        }
        //自旋时间递减
        if (spins > 0)
            spins = shouldSpin(s) ? (spins-1) : 0;

        //设置等待线程
        else if (s.waiter == null)
            s.waiter = w; // establish waiter so can park next iter

        //没有设置超时等待,线程一直挂起,知道被配对操作唤醒
        else if (!timed)
            LockSupport.park(this);    //线程挂起

        //判断超时等待时间是否大于自旋最大时间
        //若是大于,就直接将线程挂起一段时间
        //否则只自旋不挂起
        else if (nanos > spinForTimeoutThreshold)
            LockSupport.parkNanos(this, nanos);
    }
}

//需要自旋的情形
//当前结点为栈顶
//栈顶为null
//栈顶正在匹配中
boolean shouldSpin(SNode s) {
    SNode h = head;
    return (h == s || h == null || isFulfilling(h.mode));
}

//尝试配对
boolean tryMatch(SNode s) {
    //尝试将当前结点的配对结点更新为s,更新成功就唤醒当前结对应的线程
    if (match == null &&
        UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
        Thread w = waiter;
        if (w != null) {    // waiters need at most one unpark
            waiter = null;
            LockSupport.unpark(w);
        }
        return true;
    }
    return match == s;
}

    通过上面对非公平模式下TransferStack中transfer方法的分析,可知非公平模式实际上可以说是非常的不公平,因为TransferStack是利用栈的后进先出性质来进行配对的,也就说基本上都是后来先服务。其大致过程可以简化成如下图所示:

545622265e6e32fda8d5afb7593f64e6dc6.jpg

 
 
 
 
 
 
 
 
 
 
 
 

转载于:https://my.oschina.net/bzhangpoorman/blog/3044799

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值