SynchronousQueue 1.8ソースコードの解析

[TOC]

SynchronousQueue 1.8ソースコードの解析

I.はじめに

SynchronousQueueは、キューを呼び出していないいない内部データ・ストレージ・スペースので、キューは、覗き見することができない要素が存在しないため、スレッドはいずれかのキューがあるチームにスレッドまでキューに入れられたブロックします感じて、非常に奇妙なキューです手をつないで行く必要があり、エンキューを待つ必要があり、チームが同じである、一連の操作は、エンキューおよびデキューが一緒に残してあり、公正かつ不当なモードのためのキュー(スレッドを一致するキューを参照してください)、公正モードデータ構造は、非公正なモードがスタック(LIFO)で使用されるキュー(FIFO)です。

二、UMLダイアグラム

SynchronousQueue 1.8ソースコードの解析

第三に、基本的なメンバー

abstract static class Transferer<E> {
    // 出队入队都是这一个方法
    abstract E transfer(E e, boolean timed, long nanos);
}

    // npu数
    static final int NCPUS = Runtime.getRuntime().availableProcessors();

    // 带超时时间的自旋次数
    static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;

    // 没有超时的自旋次数
    static final int maxUntimedSpins = maxTimedSpins * 16;
不当な実装TransferStack、主要メンバー

TransferStackは、転写手段を継承しました

注意:転写手段を継承しているため、チームとチームからの転送方法が使用されているように、これらの状態は、重要であり、状態は区別するために使用され、方法のセクションでは、後で説明します

        /** 0表示消费者 */
        static final int REQUEST    = 0;
        /** 1表示数据的生产者 */
        static final int DATA       = 1;
        /** 2 表示数据正在匹配 */
        static final int FULFILLING = 2;

        static final class SNode {
            volatile SNode next;        // 下一个节点
            volatile SNode match;       // 匹配的节点
            volatile Thread waiter;     // 等待的线程
            Object item;                // 数据
            int mode;                   // 模式 0 , 1 , 2
        }
    /** 头结点 */
    volatile SNode head;
TransferQueue公正な実施、主要メンバー

TransferQueueは、転写手段を継承しました

    static final class QNode {
            volatile QNode next;          // next 节点
            volatile Object item;         // 数据项
            volatile Thread waiter;       // 等待线程
            final boolean isData;         // 区分生产和消费
    }

        /** 头结点 */
        transient volatile QNode head;
        /** 尾节点 */
        transient volatile QNode tail;

第四に、一般的な方法

コンストラクタ
    public SynchronousQueue() {
        this(false);
    }

    // 构造方法,fair表示公平或者非公平
    public SynchronousQueue(boolean fair) {
        transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
    }
TransferStack不当な一般的な方法
提供方法
    public boolean offer(E e) {
        // e 不能为null
        if (e == null) throw new NullPointerException();
        return transferer.transfer(e, true, 0) != null;
    }

    public boolean offer(E e, long timeout, TimeUnit unit)
            throws InterruptedException {
            // e 不能为null
        if (e == null) throw new NullPointerException();
        if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
            return true;
        if (!Thread.interrupted())
            return false;
        throw new InterruptedException();
    }
putメソッド
public void put(E e) throws InterruptedException {
    // e 不能为null
        if (e == null) throw new NullPointerException();
        if (transferer.transfer(e, false, 0) == null) {
            // 支持中断
            Thread.interrupted();
            throw new InterruptedException();

    }
投票方法
    public E poll() {
        return transferer.transfer(null, true, 0);
    }
take 方法
public E take() throws InterruptedException {
        E e = transferer.transfer(null, false, 0);
        if (e != null)
            return e;
        Thread.interrupted();
        throw new InterruptedException();
    }
転送方法
    E transfer(E e, boolean timed, long nanos) {

            SNode s = null; // constructed/reused as needed
            //  根据所传元素判断为生产or消费
            int mode = (e == null) ? REQUEST : DATA;

            for (;;) { // 无限循环
                SNode h = head; // 获取头结点
                if (h == null || h.mode == mode) {  // 头结点为空或者当前节点状态(0,1,2)和头结点相同
                    if (timed && nanos <= 0) {      // can't wait 设置有时间
                        // 节点不为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))) { // 将h设为自己的next节点
                        // 空旋或者阻塞直到s结点被FulFill操作所匹配
                        SNode m = awaitFulfill(s, timed, nanos);
                        if (m == s) {                // wait was cancelled 节点被取消了
                            clean(s);
                            return null;
                        }
                        // 找到匹配的线程了
                        // h == head 可能已经已经被匹配
                        // h.next 等于s 不同类型
                        if ((h = head) != null && h.next == s)
                            // 弹出h 和 s
                            casHead(h, s.next);     // help s's fulfiller
                        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
                            SNode m = s.next;       // m is s's match
                            // 没有下一个节点了,结束这次循环,走最外层循环重新开始
                            if (m == null) {        // all waiters are gone // m等于null
                                casHead(s, null);   // pop fulfill node // cas 设置head
                                s = null;           // use new node next time
                                break;              // restart main loop // 结束循环
                            }
                            SNode mn = m.next;
                            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.casNext(m, mn);   // help unlink //  修改next节点
                        }
                    }
                } 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
                    }
                }
            }
        }
awaitFulfill方法
    SNode awaitFulfill(SNode s, boolean timed, long nanos) {

            // 计算时间
            final long deadline = timed ? System.nanoTime() + nanos : 0L;
            // 获取当前线程
            Thread w = Thread.currentThread();
            // shouldSpin控制自旋
            // shouldSpin 用于检测当前节点是否需要自旋
            // 如果栈为空、该节点是首节点或者该节点是匹配节点,则先采用自旋,否则阻塞
            int spins = (shouldSpin(s) ?
                    (timed ? maxTimedSpins : maxUntimedSpins) : 0);
            for (;;) { // 死循环
                if (w.isInterrupted()) // 线程被中断
                    s.tryCancel();
                SNode m = s.match;
                if (m != null)  // 存在匹配节点 ,返回
                    return m;
                if (timed) { // 存在超时设置
                    nanos = deadline - System.nanoTime();
                    if (nanos <= 0L) {
                        s.tryCancel();
                        continue;
                    }
                }
                // 自旋;每次自旋的时候都需要检查自身是否满足自旋条件,满足就 - 1,否则为0
                if (spins > 0)
                    spins = shouldSpin(s) ? (spins-1) : 0;
                // 设置node的线程
                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);
            }
        }
きれいな方法
    void clean(SNode s) {
            s.item = null;   // forget item
            s.waiter = null; // forget thread

            // next节点
            SNode past = s.next;
            // next节点也被中断了,直接删除
            if (past != null && past.isCancelled())
                past = past.next;

            // Absorb cancelled nodes at head
            // 从栈顶开始找,清除取消的节点
            SNode p;
            while ((p = head) != null && p != past && p.isCancelled())
                casHead(p, p.next);

            // Unsplice embedded nodes
            // 从有效的头节点开始p ,到s的后继节点,继续清除
            while (p != null && p != past) {
                SNode n = p.next;
                if (n != null && n.isCancelled())
                    p.casNext(n, n.next);
                else
                    p = n;
            }
        }

転送方法の分析:

  • 私たちは、その転送が空またはポーリング方式はチームの中と外、それらを区別することです提供方法、であるeで判断することができました。

  • キューが空であるヘッド、又はヘッドノードのキューが存在し、同一のそれらのモードと、第1のケースが相殺最初に決定されるか、または、これらの操作の実装に動作をエンキューしていない実行され、新たに追加されたノード我々はパターンが同じで一致することはできませんので、スタックの先頭に参加し、それが中断されるまでスレッドawaitFulfillメソッドブロックを呼び出し、タイムアウトやマッチが成功すると、なぜ、ウェイク我々は唯一のスレッドまで試合の異なるモードをスレッドをブロックすることができ、詰まります自身、これは、プロセスawaitFulfill法の終わりです。

  • 第二の場合は、チームの異なるモードならば、マッチング処理を実行しないように、マッチング方法をisFulfillingがヘッドノードによって決定されます

    サイクルがこのような状況の上に、あなたはノードを一致させるために始めることができない場合は、プロセスを再起動する場合まず、ノードがキャンセルされているかどうかを決定し、その中に何の判断が一つのノードのみが、そこに彼がされていないではない、成功した別のノードをウェイクtryMatchメソッドを呼び出しますその後、スタックに沿って、結果を返し、競争一致他のスレッドが存在し得るノードを見つけるために、逆方向に進めるために、次のに失敗しました。

  • 第三の場合、異なるパターンのチームに、しかし、ヘッドノードがマッチングされ、それが試合を完了するのに役立つだろうし、その後サイクル全体を再取ります。
TransferQueue共通持分法

チームとチームは、我々は、メインバーの転送方法を見て、同じ方法です。

転送方法
    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
                // h==t 刚刚初始化 t.isData == isData,尾节点和当前节点的类型一样
                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 QNode(e, isData);
                    if (!t.casNext(null, s))       // failed to link in 有竞争
                        continue;

                    // 替换尾节点
                    advanceTail(t, s);              // swing tail and wait
                    // 自旋/阻塞 返回的是中断取消/匹配的节点
                    Object x = awaitFulfill(s, e, timed, nanos);
                    // 中断
                    if (x == s) {                   // wait was cancelled
                        clean(t, s);
                        return null;
                    }

                    // 匹配成功了,需要执行出队操作
                    if (!s.isOffList()) {
                        // not already unlinked
                        // 修改头结点
                        advanceHead(t, s);          // unlink if head
                        if (x != null)              // and forget fields
                            s.item = s;
                        s.waiter = null;
                    }
                    return (x != null) ? (E)x : e;

                } else {                            // complementary-mode
                    // 出队从头元素开始
                    QNode m = h.next;               // node to fulfill
                    if (t != tail || m == null || h != head) // 队列发生变化重来
                        continue;                   // inconsistent read

                    Object x = m.item;
                    // isData == (x != null) 判断模式是否相同,不相同才能匹配
                    // x == m 说明已经被中断或者超时了
                    // m.casItem(x, e) 匹配
                    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); // 唤醒线程
                    return (x != null) ? (E)x : e;
                }
            }
        }

転送方法の分析:

  • Eはまた、すべてのコール転送方式、転写法は、2つの部分、エンキューおよびマッチングに見ることができる、エンキューまたはデキューすることによって判定されます。
  • チームの第1の部分は、チームモデルは、エンドノードが変更されていない決定、エンド・ノードを取得し、テール・ノードから開始同じエンキューされ、マルチスレッドが存在し得る、再反復する変化は、何尾を決定していませんノードは、ブレークするまで、現在のノードを遮断awaitFulfill呼び出して、それが新しいノードを追加し、別のスレッドがある示し、tailノードを更新する必要があり、何の次のノードを持っていない、し、現在の次のノードのエンド・ノードに参加する新しいノードを構築し、テール・ノードを更新しますアウトまたは一致し、成功する一致ノードをクリアし、きれいなメソッドを呼び出します。
  • マッチ(チーム)の第2の部分は、チームは、ウェイクmはスレッドを待機スクラッチノードから起動し、一致が成功した場合、異なるモードは、キャンセルした場合、実際には、項目を設定CAS、データの転送であるか否かを決定することであり、ここで注意私たちが最初に一致し、次のノードのノードを取得するため、ヘッドノードmになるように設定、実際には、m個のノードは、ポップアップ表示します。

V.の概要

SynchronousQueue実装は非常に複雑であり、我々はブロッキングキューものの、しかし、ロックを使用していないことがわかります。配信シナリオのキューは、何のキューキュー記憶素子、チームと手をつないで行かなければならないチームはありません。

参考「アートのJava並行プログラミング。」

おすすめ

転載: blog.51cto.com/14220760/2416470