精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

沒研究過SynchronousQueue源碼,就別寫精通線程池

開發(fā) 前端
無論是ArrayBlockingQueue還是LinkedBlockingQueue都是起到緩沖隊(duì)列的作用,當(dāng)消費(fèi)者的消費(fèi)速度跟不上時(shí),任務(wù)就在隊(duì)列中堆積,需要等待消費(fèi)者慢慢消費(fèi)。

引言

前面文章我們講解了ArrayBlockingQueue和LinkedBlockingQueue源碼,這篇文章開始講解SynchronousQueue源碼。從名字上就能看到ArrayBlockingQueue是基于數(shù)組實(shí)現(xiàn)的,而LinkedBlockingQueue是基于鏈表實(shí)現(xiàn),而SynchronousQueue是基于什么數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,看不來。

無論是ArrayBlockingQueue還是LinkedBlockingQueue都是起到緩沖隊(duì)列的作用,當(dāng)消費(fèi)者的消費(fèi)速度跟不上時(shí),任務(wù)就在隊(duì)列中堆積,需要等待消費(fèi)者慢慢消費(fèi)。

如果我們想要自己的任務(wù)快速執(zhí)行,不要積壓在隊(duì)列中,該怎么辦? 今天的主角SynchronousQueue就派上用場了。

SynchronousQueue被稱為同步隊(duì)列,當(dāng)生產(chǎn)者往隊(duì)列中放元素的時(shí)候,必須等待消費(fèi)者把這個(gè)元素取走,否則一直阻塞。消費(fèi)者取元素的時(shí)候,同理也必須等待生產(chǎn)者放隊(duì)列中放元素。

由于SynchronousQueue實(shí)現(xiàn)了BlockingQueue接口,而BlockingQueue接口中定義了幾組放數(shù)據(jù)和取數(shù)據(jù)的方法,來滿足不同的場景。

操作

拋出異常

返回特定值

一直阻塞

阻塞指定時(shí)間

放數(shù)據(jù)

add()

offer()

put()

offer(e, time, unit)

取數(shù)據(jù)(同時(shí)刪除數(shù)據(jù))

remove()

poll()

take()

poll(time, unit)

取數(shù)據(jù)(不刪除)

element()

peek()

不支持

不支持

SynchronousQueue也會(huì)有針對(duì)這幾組放數(shù)據(jù)和取數(shù)據(jù)方法的具體實(shí)現(xiàn)。

Java線程池中的帶緩存的線程池就是基于SynchronousQueue實(shí)現(xiàn)的:

// 創(chuàng)建帶緩存的線程池
ExecutorService executorService = Executors.newCachedThreadPool();

對(duì)應(yīng)的源碼實(shí)現(xiàn):

// 底層使用SynchronousQueue隊(duì)列處理任務(wù)
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
            60L, TimeUnit.SECONDS,
            new SynchronousQueue<Runnable>());
}

類結(jié)構(gòu)

先看一下SynchronousQueue類里面有哪些屬性:

public class SynchronousQueue<E>
        extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {

    /**
     * 轉(zhuǎn)接器(棧和隊(duì)列的父類)
     */
    abstract static class Transferer<E> {
        
        /**
         * 轉(zhuǎn)移(put和take都用這一個(gè)方法)
         *
         * @param e     元素
         * @param timed 是否超時(shí)
         * @param nanos 納秒
         */
        abstract E transfer(E e, boolean timed, long nanos);
        
    }

    /**
     * 棧實(shí)現(xiàn)類
     */
    static final class TransferStack<E> extends Transferer<E> {
    }

    /**
     * 隊(duì)列實(shí)現(xiàn)類
     */
    static final class TransferQueue<E> extends Transferer<E> {
    }

}

SynchronousQueue底層是基于Transferer抽象類實(shí)現(xiàn)的,放數(shù)據(jù)和取數(shù)據(jù)的邏輯都耦合在transfer()方法中。而Transferer抽象類又有兩個(gè)實(shí)現(xiàn)類,分別是基于棧結(jié)構(gòu)實(shí)現(xiàn)和基于隊(duì)列實(shí)現(xiàn)。

初始化

SynchronousQueue常用的初始化方法有兩個(gè):

  1. 無參構(gòu)造方法
  2. 指定容量大小的有參構(gòu)造方法
/**
 * 無參構(gòu)造方法
 */
BlockingQueue<Integer> blockingQueue1 = new SynchronousQueue<>();

/**
 * 有參構(gòu)造方法,指定是否使用公平鎖(默認(rèn)使用非公平鎖)
 */
BlockingQueue<Integer> blockingQueue2 = new SynchronousQueue<>(true);

再看一下對(duì)應(yīng)的源碼實(shí)現(xiàn):

/**
 * 無參構(gòu)造方法
 */
public SynchronousQueue() {
    this(false);
}

/**
 * 有參構(gòu)造方法,指定是否使用公平鎖
 */
public SynchronousQueue(boolean fair) {
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

可以看出SynchronousQueue的無參構(gòu)造方法默認(rèn)使用的非公平策略,有參構(gòu)造方法可以指定使用公平策略。操作策略:

  1. 公平策略,基于隊(duì)列實(shí)現(xiàn)的是公平策略,先進(jìn)先出。
  2. 非公平策略,基于棧實(shí)現(xiàn)的是非公平策略,先進(jìn)后出。

棧實(shí)現(xiàn)

棧的類結(jié)構(gòu)

/**
 * 棧實(shí)現(xiàn)
 */
static final class TransferStack<E> extends Transferer<E> {

    /**
     * 頭節(jié)點(diǎn)(也是棧頂節(jié)點(diǎn))
     */
    volatile SNode head;

    /**
     * 棧節(jié)點(diǎn)類
     */
    static final class SNode {

        /**
         * 當(dāng)前操作的線程
         */
        volatile Thread waiter;

        /**
         * 節(jié)點(diǎn)值(取數(shù)據(jù)的時(shí)候,該字段為null)
         */
        Object item;

        /**
         * 節(jié)點(diǎn)模式(也叫操作類型)
         */
        int mode;

        /**
         * 后繼節(jié)點(diǎn)
         */
        volatile SNode next;

        /**
         * 匹配到的節(jié)點(diǎn)
         */
        volatile SNode match;

    }
}

節(jié)點(diǎn)模式有以下三種:

類型值

類型描述

作用

0

REQUEST

表示取數(shù)據(jù)

1

DATA

表示放數(shù)據(jù)

2

FULFILLING

表示正在執(zhí)行中(比如取數(shù)據(jù)的線程正在匹配放數(shù)據(jù)的線程)

圖片圖片

棧的transfer方法實(shí)現(xiàn)

transfer()方法中,把放數(shù)據(jù)和取數(shù)據(jù)的邏輯耦合在一塊了,邏輯有點(diǎn)繞,不過核心邏輯就四點(diǎn),把握住就能豁然開朗。其實(shí)就是從棧頂壓入,從棧頂彈出。

詳細(xì)流程如下:

  1. 首先判斷當(dāng)前線程的操作類型與棧頂節(jié)點(diǎn)的操作類型是否一致,比如都是放數(shù)據(jù),或者都是取數(shù)據(jù)。
  2. 如果是一致,把當(dāng)前操作包裝成SNode節(jié)點(diǎn),壓入棧頂,并掛起當(dāng)前線程。
  3. 如果不一致,表示相互匹配(比如當(dāng)前操作是放數(shù)據(jù),而棧頂節(jié)點(diǎn)是取數(shù)據(jù),或者相反)。然后也把當(dāng)前操作包裝成SNode節(jié)點(diǎn)壓入棧頂,并使用tryMatch()方法匹配兩個(gè)節(jié)點(diǎn),匹配成功后,彈出兩個(gè)這兩個(gè)節(jié)點(diǎn),并喚醒棧頂節(jié)點(diǎn)線程,同時(shí)把數(shù)據(jù)傳遞給棧頂節(jié)點(diǎn)線程,最后返回。
  4. 棧頂節(jié)點(diǎn)線程被喚醒,繼續(xù)執(zhí)行,然后返回傳遞過來的數(shù)據(jù)。
/**
 * 轉(zhuǎn)移(put和take都用這一個(gè)方法)
 *
 * @param e     元素(取數(shù)據(jù)的時(shí)候,元素為null)
 * @param timed 是否超時(shí)
 * @param nanos 納秒
 */
E transfer(E e, boolean timed, long nanos) {
    SNode s = null;
    // 1. e為null,表示要取數(shù)據(jù),否則是放數(shù)據(jù)
    int mode = (e == null) ? REQUEST : DATA;
    for (; ; ) {
        SNode h = head;
        // 2. 如果本次操作跟棧頂節(jié)點(diǎn)模式相同(都是取數(shù)據(jù),或者都是放數(shù)據(jù)),就把本次操作包裝成SNode,壓入棧頂
        if (h == null || h.mode == mode) {
            if (timed && nanos <= 0) {
                if (h != null && h.isCancelled()) {
                    casHead(h, h.next);
                } else {
                    return null;
                }
                // 3. 把本次操作包裝成SNode,壓入棧頂,并掛起當(dāng)前線程
            } else if (casHead(h, s = snode(s, e, h, mode))) {
                // 4. 掛起當(dāng)前線程
                SNode m = awaitFulfill(s, timed, nanos);
                if (m == s) {
                    clean(s);
                    return null;
                }
                // 5. 當(dāng)前線程被喚醒后,如果棧頂有了新節(jié)點(diǎn),就刪除當(dāng)前節(jié)點(diǎn)
                if ((h = head) != null && h.next == s) {
                    casHead(h, s.next);
                }
                return (E) ((mode == REQUEST) ? m.item : s.item);
            }
            // 6. 如果棧頂節(jié)點(diǎn)類型跟本次操作不同,并且模式不是FULFILLING類型
        } else if (!isFulfilling(h.mode)) {
            if (h.isCancelled()) {
                casHead(h, h.next);
            }
            // 7. 把本次操作包裝成SNode(類型是FULFILLING),壓入棧頂
            else if (casHead(h, s = snode(s, e, h, FULFILLING | mode))) {
                // 8. 使用死循環(huán),直到匹配到對(duì)應(yīng)的節(jié)點(diǎn)
                for (; ; ) {
                    // 9. 遍歷下個(gè)節(jié)點(diǎn)
                    SNode m = s.next;
                    // 10. 如果節(jié)點(diǎn)是null,表示遍歷到末尾,設(shè)置棧頂節(jié)點(diǎn)是null,結(jié)束。
                    if (m == null) {
                        casHead(s, null);
                        s = null;
                        break;
                    }
                    SNode mn = m.next;
                    // 11. 如果棧頂?shù)暮罄^節(jié)點(diǎn)跟棧頂節(jié)點(diǎn)匹配成功,就刪除這兩個(gè)節(jié)點(diǎn),結(jié)束。
                    if (m.tryMatch(s)) {
                        casHead(s, mn);
                        return (E) ((mode == REQUEST) ? m.item : s.item);
                    } else {
                        // 12. 如果沒有匹配成功,就刪除棧頂?shù)暮罄^節(jié)點(diǎn),繼續(xù)匹配
                        s.casNext(m, mn);
                    }
                }
            }
        } else {
            // 13. 如果棧頂節(jié)點(diǎn)類型跟本次操作不同,并且是FULFILLING類型,
            // 就再執(zhí)行一遍上面第8步for循環(huán)中的邏輯(很少概率出現(xiàn))
            SNode m = h.next;
            if (m == null) {
                casHead(h, null);
            } else {
                SNode mn = m.next;
                if (m.tryMatch(h)) {
                    casHead(h, mn);
                } else {
                    h.casNext(m, mn);
                }
            }
        }
    }
}

不用關(guān)心細(xì)枝末節(jié),把握住代碼核心邏輯即可。 再看一下第4步,掛起線程的代碼邏輯: 核心邏輯就兩條:

  • 第6步,掛起當(dāng)前線程
  • 第3步,當(dāng)前線程被喚醒后,直接返回傳遞過來的match節(jié)點(diǎn)
/**
 * 等待執(zhí)行
 *
 * @param s     節(jié)點(diǎn)
 * @param timed 是否超時(shí)
 * @param nanos 超時(shí)時(shí)間
 */
SNode awaitFulfill(SNode s, boolean timed, long nanos) {
    // 1. 計(jì)算超時(shí)時(shí)間
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    Thread w = Thread.currentThread();
    // 2. 計(jì)算自旋次數(shù)
    int spins = (shouldSpin(s) ?
            (timed ? maxTimedSpins : maxUntimedSpins) : 0);
    for (; ; ) {
        if (w.isInterrupted())
            s.tryCancel();
        // 3. 如果已經(jīng)匹配到其他節(jié)點(diǎn),直接返回
        SNode m = s.match;
        if (m != null)
            return m;
        if (timed) {
            // 4. 超時(shí)時(shí)間遞減
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                s.tryCancel();
                continue;
            }
        }
        // 5. 自旋次數(shù)減一
        if (spins > 0)
            spins = shouldSpin(s) ? (spins - 1) : 0;
        else if (s.waiter == null)
            s.waiter = w;
            // 6. 開始掛起當(dāng)前線程
        else if (!timed)
            LockSupport.park(this);
        else if (nanos > spinForTimeoutThreshold)
            LockSupport.parkNanos(this, nanos);
    }
}

再看一下匹配節(jié)點(diǎn)的tryMatch()方法邏輯: 作用就是喚醒棧頂節(jié)點(diǎn),并當(dāng)前節(jié)點(diǎn)傳遞給棧頂節(jié)點(diǎn)。

/**
 * 匹配節(jié)點(diǎn)
 *
 * @param s 當(dāng)前節(jié)點(diǎn)
 */
boolean tryMatch(SNode s) {
    if (match == null &&
            UNSAFE.compareAndSwapObject(this, matchOffset, null, s)) {
        Thread w = waiter;
        if (w != null) {
            waiter = null;
            // 1. 喚醒棧頂節(jié)點(diǎn)
            LockSupport.unpark(w);
        }
        return true;
    }
    // 2. 把當(dāng)前節(jié)點(diǎn)傳遞給棧頂節(jié)點(diǎn)
    return match == s;
}

隊(duì)列實(shí)現(xiàn)

隊(duì)列的類結(jié)構(gòu)

/**
 * 隊(duì)列實(shí)現(xiàn)
 */
static final class TransferQueue<E> extends Transferer<E> {

    /**
     * 頭節(jié)點(diǎn)
     */
    transient volatile QNode head;

    /**
     * 尾節(jié)點(diǎn)
     */
    transient volatile QNode tail;

    /**
     * 隊(duì)列節(jié)點(diǎn)類
     */
    static final class QNode {

        /**
         * 當(dāng)前操作的線程
         */
        volatile Thread waiter;

        /**
         * 節(jié)點(diǎn)值
         */
        volatile Object item;

        /**
         * 后繼節(jié)點(diǎn)
         */
        volatile QNode next;

        /**
         * 當(dāng)前節(jié)點(diǎn)是否為數(shù)據(jù)節(jié)點(diǎn)
         */
        final boolean isData;
    }
}

可以看出TransferQueue隊(duì)列是使用帶有頭尾節(jié)點(diǎn)的單鏈表實(shí)現(xiàn)的。 還有一點(diǎn)需要提一下,TransferQueue默認(rèn)構(gòu)造方法,會(huì)初始化頭尾節(jié)點(diǎn),默認(rèn)是空節(jié)點(diǎn)。

/**
 * TransferQueue默認(rèn)的構(gòu)造方法
 */
TransferQueue() {
    QNode h = new QNode(null, false);
    head = h;
    tail = h;
}

隊(duì)列的transfer方法實(shí)現(xiàn)

隊(duì)列使用的公平策略,體現(xiàn)在,每次操作的時(shí)候,都是從隊(duì)尾壓入,從隊(duì)頭彈出。 詳細(xì)流程如下:

  1. 首先判斷當(dāng)前線程的操作類型與隊(duì)尾節(jié)點(diǎn)的操作類型是否一致,比如都是放數(shù)據(jù),或者都是取數(shù)據(jù)。
  2. 如果是一致,把當(dāng)前操作包裝成QNode節(jié)點(diǎn),壓入隊(duì)尾,并掛起當(dāng)前線程。
  3. 如果不一致,表示相互匹配(比如當(dāng)前操作是放數(shù)據(jù),而隊(duì)尾節(jié)點(diǎn)是取數(shù)據(jù),或者相反)。然后在隊(duì)頭節(jié)點(diǎn)開始遍歷,找到與當(dāng)前操作類型相匹配的節(jié)點(diǎn),把當(dāng)前操作的節(jié)點(diǎn)值傳遞給這個(gè)節(jié)點(diǎn),并彈出這個(gè)節(jié)點(diǎn),喚醒這個(gè)節(jié)點(diǎn)的線程,最后返回。
  4. 隊(duì)頭節(jié)點(diǎn)線程被喚醒,繼續(xù)執(zhí)行,然后返回傳遞過來的數(shù)據(jù)。
/**
 * 轉(zhuǎn)移(put和take都用這一個(gè)方法)
 *
 * @param e     元素(取數(shù)據(jù)的時(shí)候,元素為null)
 * @param timed 是否超時(shí)
 * @param nanos 超時(shí)時(shí)間
 */
E transfer(E e, boolean timed, long nanos) {
    QNode s = null;
    // 1. e不為null,表示要放數(shù)據(jù),否則是取數(shù)據(jù)
    boolean isData = (e != null);
    for (; ; ) {
        QNode t = tail;
        QNode h = head;
        if (t == null || h == null) {
            continue;
        }

        // 2. 如果本次操作跟隊(duì)尾節(jié)點(diǎn)模式相同(都是取數(shù)據(jù),或者都是放數(shù)據(jù)),就把本次操作包裝成QNode,壓入隊(duì)尾
        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;
            }
            // 3. 把本次操作包裝成QNode,壓入隊(duì)尾
            if (s == null) {
                s = new QNode(e, isData);
            }
            if (!t.casNext(null, s)) {
                continue;
            }
            advanceTail(t, s);
            // 4. 掛起當(dāng)前線程
            Object x = awaitFulfill(s, e, timed, nanos);
            // 5. 當(dāng)前線程被喚醒后,返回返回傳遞過來的節(jié)點(diǎn)值
            if (x == s) {
                clean(t, s);
                return null;
            }
            if (!s.isOffList()) {
                advanceHead(t, s);
                if (x != null) {
                    s.item = s;
                }
                s.waiter = null;
            }
            return (x != null) ? (E) x : e;
        } else {
            // 6. 如果本次操作跟隊(duì)尾節(jié)點(diǎn)模式不同,就從隊(duì)頭結(jié)點(diǎn)開始遍歷,找到模式相匹配的節(jié)點(diǎn)
            QNode m = h.next;
            if (t != tail || m == null || h != head) {
                continue;
            }

            Object x = m.item;
            // 7. 把當(dāng)前節(jié)點(diǎn)值e傳遞給匹配到的節(jié)點(diǎn)m
            if (isData == (x != null) || x == m ||
                    !m.casItem(x, e)) {
                advanceHead(h, m);
                continue;
            }
            // 8. 彈出隊(duì)頭節(jié)點(diǎn),并喚醒節(jié)點(diǎn)m
            advanceHead(h, m);
            LockSupport.unpark(m.waiter);
            return (x != null) ? (E) x : e;
        }
    }
}

看完了底層源碼,再看一下上層包裝好的工具方法。

放數(shù)據(jù)源碼

放數(shù)據(jù)的方法有四個(gè):

操作

拋出異常

返回特定值

阻塞

阻塞一段時(shí)間

放數(shù)據(jù)

add()

offer()

put()

offer(e, time, unit)

offer方法源碼

先看一下offer()方法源碼,其他放數(shù)據(jù)方法邏輯也是大同小異,底層都是調(diào)用的transfer()方法實(shí)現(xiàn)。 如果沒有匹配到合適的節(jié)點(diǎn),offer()方法會(huì)直接返回false,表示插入失敗。

/**
 * offer方法入口
 *
 * @param e 元素
 * @return 是否插入成功
 */
public boolean offer(E e) {
    // 1. 判空,傳參不允許為null
    if (e == null) {
        throw new NullPointerException();
    }
    // 2. 調(diào)用底層transfer方法
    return transferer.transfer(e, true, 0) != null;
}

再看一下另外三個(gè)添加元素方法源碼:

add方法源碼

如果沒有匹配到合適的節(jié)點(diǎn),add()方法會(huì)拋出異常,底層基于offer()實(shí)現(xiàn)。

/**
 * add方法入口
 *
 * @param e 元素
 * @return 是否添加成功
 */
public boolean add(E e) {
    if (offer(e)) {
        return true;
    } else {
        throw new IllegalStateException("Queue full");
    }
}

put方法源碼

如果沒有匹配到合適的節(jié)點(diǎn),put()方法會(huì)一直阻塞,直到有其他線程取走數(shù)據(jù),才能添加成功。

/**
 * put方法入口
 *
 * @param e 元素
 */
public void put(E e) throws InterruptedException {
    // 1. 判空,傳參不允許為null
    if (e == null) {
        throw new NullPointerException();
    }
    // 2. 調(diào)用底層transfer方法
    if (transferer.transfer(e, false, 0) == null) {
        Thread.interrupted();
        throw new InterruptedException();
    }
}

offer(e, time, unit)源碼

再看一下offer(e, time, unit)方法源碼,如果沒有匹配到合適的節(jié)點(diǎn), offer(e, time, unit)方法會(huì)阻塞一段時(shí)間,然后返回false。

/**
 * offer方法入口
 *
 * @param e       元素
 * @param timeout 超時(shí)時(shí)間
 * @param unit    時(shí)間單位
 * @return 是否添加成功
 */
public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
    // 1. 判空,傳參不允許為null
    if (e == null) {
        throw new NullPointerException();
    }
    // 2. 調(diào)用底層transfer方法
    if (transferer.transfer(e, true, unit.toNanos(timeout)) != null) {
        return true;
    }
    if (!Thread.interrupted()) {
        return false;
    }
    throw new InterruptedException();
}

彈出數(shù)據(jù)源碼

彈出數(shù)據(jù)(取出數(shù)據(jù)并刪除)的方法有四個(gè):

操作

拋出異常

返回特定值

阻塞

阻塞一段時(shí)間

取數(shù)據(jù)(同時(shí)刪除數(shù)據(jù))

remove()

poll()

take()

poll(time, unit)

poll方法源碼

看一下poll()方法源碼,其他方取數(shù)據(jù)法邏輯大同小異,底層都是調(diào)用的transfer方法實(shí)現(xiàn)。 poll()方法在彈出元素的時(shí)候,如果沒有匹配到合適的節(jié)點(diǎn),直接返回null,表示彈出失敗。

/**
 * poll方法入口
 */
public E poll() {
    // 調(diào)用底層transfer方法
    return transferer.transfer(null, true, 0);
}

remove方法源碼

再看一下remove()方法源碼,如果沒有匹配到合適的節(jié)點(diǎn),remove()會(huì)拋出異常。

/**
 * remove方法入口
 */
public E remove() {
    // 1. 直接調(diào)用poll方法
    E x = poll();
    // 2. 如果取到數(shù)據(jù),直接返回,否則拋出異常
    if (x != null) {
        return x;
    } else {
        throw new NoSuchElementException();
    }
}

take方法源碼

再看一下take()方法源碼,如果沒有匹配到合適的節(jié)點(diǎn),take()方法就一直阻塞,直到被喚醒。

/**
 * take方法入口
 */
public E take() throws InterruptedException {
    // 調(diào)用底層transfer方法
    E e = transferer.transfer(null, false, 0);
    if (e != null) {
        return e;
    }
    Thread.interrupted();
    throw new InterruptedException();
}

poll(time, unit)源碼

再看一下poll(time, unit)方法源碼,如果沒有匹配到合適的節(jié)點(diǎn), poll(time, unit)方法會(huì)阻塞指定時(shí)間,然后然后null。

/**
 * poll方法入口
 *
 * @param timeout 超時(shí)時(shí)間
 * @param unit    時(shí)間單位
 * @return 元素
 */
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    // 調(diào)用底層transfer方法
    E e = transferer.transfer(null, true, unit.toNanos(timeout));
    if (e != null || !Thread.interrupted()) {
        return e;
    }
    throw new InterruptedException();
}

查看數(shù)據(jù)源碼

再看一下查看數(shù)據(jù)源碼,查看數(shù)據(jù),并不刪除數(shù)據(jù)。

操作

拋出異常

返回特定值

阻塞

阻塞一段時(shí)間

取數(shù)據(jù)(不刪除)

element()

peek()

不支持

不支持

peek方法源碼

先看一下peek()方法源碼,直接返回null,SynchronousQueue不支持這種操作。

/**
 * peek方法入口
 */
public E peek() {
    return null;
}

element方法源碼

再看一下element()方法源碼,底層調(diào)用的也是peek()方法,也是不支持這種操作。

/**
 * element方法入口
 */
public E element() {
    // 1. 調(diào)用peek方法查詢數(shù)據(jù)
    E x = peek();
    // 2. 如果查到數(shù)據(jù),直接返回
    if (x != null) {
        return x;
    } else {
        // 3. 如果沒找到,則拋出異常
        throw new NoSuchElementException();
    }
}

總結(jié)

這篇文章講解了SynchronousQueue阻塞隊(duì)列的核心源碼,了解到SynchronousQueue隊(duì)列具有以下特點(diǎn):

  1. SynchronousQueue實(shí)現(xiàn)了BlockingQueue接口,提供了四組放數(shù)據(jù)和讀數(shù)據(jù)的方法,來滿足不同的場景。
  2. SynchronousQueue底層有兩種實(shí)現(xiàn)方式,分別是基于棧實(shí)現(xiàn)非公平策略,以及基于隊(duì)列實(shí)現(xiàn)的公平策略。
  3. SynchronousQueue初始化的時(shí)候,可以指定使用公平策略還是非公平策略。
  4. SynchronousQueue不存儲(chǔ)元素,不適合作為緩存隊(duì)列使用。適用于生產(chǎn)者與消費(fèi)者速度相匹配的場景,可減少任務(wù)執(zhí)行的等待時(shí)間。
責(zé)任編輯:武曉燕 來源: 一燈架構(gòu)
相關(guān)推薦

2023-12-28 07:49:11

線程池源碼應(yīng)用場景

2013-05-28 13:57:12

MariaDB

2022-12-16 08:31:37

調(diào)度線程池源碼

2025-09-24 18:39:45

2015-03-24 16:29:55

默認(rèn)線程池java

2021-07-12 08:39:14

程序員外賣小哥代碼

2020-09-21 08:33:12

線程池調(diào)度Thread Pool

2025-01-03 08:40:53

Java并發(fā)編程Guava庫

2020-06-11 16:15:25

Java線程池代碼

2022-09-26 00:48:14

線程池阻塞數(shù)據(jù)

2015-10-10 09:39:42

Java線程池源碼解析

2018-10-31 15:54:47

Java線程池源碼

2013-06-08 10:11:31

Java線程池架構(gòu)

2022-06-24 06:43:57

線程池線程復(fù)用

2021-05-26 11:30:24

Java線程池代碼

2023-03-06 08:56:57

2020-04-03 10:57:09

文檔分支項(xiàng)目

2024-01-29 15:54:41

Java線程池公平鎖

2023-05-19 08:01:24

Key消費(fèi)場景

2021-09-17 11:08:05

內(nèi)存
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

日本色护士高潮视频在线观看 | 午夜精品一区二区三区在线视| 免费在线观看日韩av| 91九色在线看| 国产精品视频yy9299一区| 亚洲一区二区三区777| 91精品天堂| 欧美精品一区二区蜜桃| 中国av一区| 91精品国产欧美日韩| 日韩免费一级视频| 午夜视频在线观看网站| a美女胸又www黄视频久久| 国产精品丝袜视频| 国产精品18p| 日韩在线视频精品| 亚洲精品狠狠操| 图片区乱熟图片区亚洲| 亚洲精品一级二级| 亚洲一级在线观看| 正在播放91九色| 欧美少妇另类| 成人国产精品免费| 国产一区二区在线免费| 免费观看一区二区三区毛片| 91精品一区二区三区综合| 亚洲欧美一区二区三区四区| 中文字幕一二三区| 欧美黄色网络| 日本高清成人免费播放| 久久久久久www| 影音先锋中文在线视频| 国产精品久久久久影院亚瑟| 免费成人看片网址| 人妻中文字幕一区| 国产一区二区不卡| 成人xxxx视频| 这里只有精品9| 日韩激情一二三区| 国产精品mp4| 天天操中文字幕| 中文高清一区| 久久久免费精品视频| 老妇女50岁三级| 自拍日韩欧美| 久久视频中文字幕| 婷婷伊人五月天| 久久神马影院| www.久久撸.com| 日韩精品久久久久久久的张开腿让| 欧洲专线二区三区| 亚洲视频国产视频| 尤物视频最新网址| 国产一区二区区别| 国产亚洲精品va在线观看| 日本少妇高潮喷水xxxxxxx| 色婷婷精品视频| 亚洲精品国产suv| 久久亚洲AV成人无码国产野外| 久久久久97| 亚洲精品视频免费| 亚洲精品成人无码| 成人羞羞网站| 久久伊人色综合| 欧美国产在线看| 欧美三级黄美女| 国模视频一区二区三区| 日韩欧美激情视频| 性欧美精品高清| 国产九九精品视频| 国产免费不卡av| 成人深夜在线观看| 就去色蜜桃综合| 国产区av在线| 亚洲欧美色一区| 国产女主播自拍| 日韩电影免费观| 欧美日韩国产高清一区二区| 人妻巨大乳一二三区| 免费福利视频一区| 怡红院精品视频| caoporn91| 亚洲高清毛片| 国产精品国产福利国产秒拍| 国产精品热久久| 风间由美性色一区二区三区| 久久国产精品久久精品国产| 99reav在线| 亚洲在线视频免费观看| 国产乱子夫妻xx黑人xyx真爽| jvid一区二区三区| 精品日韩一区二区三区| 无码h肉动漫在线观看| 国产精品麻豆久久| 97在线观看视频| 中文字幕制服诱惑| 大陆成人av片| 亚洲mv在线看| 国产理论在线| 日韩一区二区三区视频在线| 中文字幕在线观看网址| 久久精品国内一区二区三区水蜜桃| 久久久久久久网站| 这里只有精品999| 成人精品亚洲人成在线| 亚洲第一导航| 国产美女高潮在线观看| 欧美一三区三区四区免费在线看| 亚洲AV无码国产精品| 欧美 日韩 国产 一区| 国产成人在线一区| 殴美一级特黄aaaaaa| 国产精品理论在线观看| 欧美日韩黄色一级片| 日本成人手机在线| 最近更新的2019中文字幕| 日本三级理论片| 久久66热偷产精品| 日本在线播放一区| 国产精品高颜值在线观看| 欧美一级黄色录像| 亚洲天堂最新地址| 香蕉久久a毛片| 国产有色视频色综合| 哥也色在线视频| 欧美日韩久久不卡| jizz中文字幕| 欧美资源在线| 你懂的网址一区二区三区| 第一av在线| 欧美电视剧在线看免费| 污污的视频在线免费观看| 人人爽香蕉精品| 欧美裸体网站| videos性欧美另类高清| 欧美精品一区二区在线观看| 国产大片免费看| 狠狠色2019综合网| 一区二区三区四区五区精品| 日韩网站中文字幕| 亚洲欧美综合图区| 91video| av不卡免费电影| 国产一级爱c视频| 久久中文字幕导航| 992tv成人免费影院| 亚州精品国产精品乱码不99按摩| 亚洲国产美女搞黄色| 国产精品偷伦视频免费观看了| 亚洲澳门在线| 99re资源| 国产夫妻在线播放| 亚洲欧美中文日韩在线| 无码人妻一区二区三区免费| 国产日韩三级在线| 蜜臀av免费观看| 亚洲精品在线观看91| 91青草视频久久| 尤物视频在线看| 亚洲福利视频二区| 日本特级黄色片| 久久精品这里都是精品| 91最新在线观看| 久久高清免费| 91观看网站| sm捆绑调教国产免费网站在线观看| 欧美精品一区二区三区蜜臀| wwwxxx亚洲| 欧美—级在线免费片| 久久综合在线观看| 亚洲国内自拍| 日本午夜精品一区二区三区| 欧美网站免费| 欧美激情区在线播放| 涩涩视频在线观看免费| 91黄视频在线| 波多野结衣在线网址| 成人看片黄a免费看在线| 日韩免费毛片视频| 97人人精品| 国产欧美丝袜| 91大神在线观看线路一区| 日韩一区av在线| 日韩在线视频第一页| 91久久奴性调教| 九九热精品免费视频| 久久综合色之久久综合| 57pao国产成永久免费视频| 国一区二区在线观看| 日韩三级电影| baoyu135国产精品免费| 国产va免费精品高清在线观看| 欧美日韩视频在线播放| 日韩av在线免费| 国产又黄又猛又爽| 色综合久久久久综合99| 欧美另类videoxo高潮| 91视频观看视频| 在线视频一二区| 日本sm残虐另类| 蜜臀av色欲a片无码精品一区 | 日韩久久久久久久| 日韩在线观看一区二区三区| 国产91在线播放九色快色| 在线播放蜜桃麻豆| 国产亚洲欧美日韩精品| 丰满人妻av一区二区三区| 欧美性生活大片视频| 香蕉视频一区二区| 亚洲桃色在线一区| 精品无码人妻一区二区免费蜜桃| 粉嫩蜜臀av国产精品网站| 欧美精品久久久久久久久25p| 日韩网站在线| 国产精品日韩三级| 99久久精品费精品国产| 日本成人黄色免费看| 精品深夜福利视频| 97久久夜色精品国产九色| 91精品国产经典在线观看| 欧美一区二三区| √天堂8资源中文在线| 久热精品视频在线观看| 在线播放麻豆| 中文字幕在线亚洲| 精品资源在线看| 国产视频精品免费播放| 欧美一区二区公司| 日韩你懂的在线观看| 国产剧情久久久| 欧美日韩一卡二卡| 伊人久久中文字幕| 91成人在线精品| 特黄视频免费看| 大桥未久av一区二区三区| 亚欧洲精品在线视频| 亚洲成a人在线观看| 精品亚洲永久免费| 亚洲国产精品一区二区久久| 免费人成在线观看| 一区二区三区91| 九九热国产精品视频| 一区二区三区日本| 免看一级a毛片一片成人不卡| 一区二区三区在线免费观看| 玖玖爱免费视频| 亚洲国产视频一区二区| 日韩成人免费在线观看| 天天综合网 天天综合色| 亚洲精品www久久久久久| 亚洲国产色一区| 成年人视频在线免费看| 色94色欧美sute亚洲线路一久| 伊人久久久久久久久久久久| 色综合久久天天| 曰批又黄又爽免费视频| 在线91免费看| 性生活免费网站| 亚洲精品美女久久久| 黄网站在线观看| 中文字幕视频在线免费欧美日韩综合在线看| 国产三级在线看| 中文字幕9999| av网站在线看| 久久噜噜噜精品国产亚洲综合| 成人免费网站观看| 国产精品久久久久久av下载红粉 | 美女精品在线| 2025韩国理伦片在线观看| 精品一区二区三区在线观看| 巨乳女教师的诱惑| 99久久精品免费看国产免费软件| 精品人妻无码一区二区三区| 国产精品天干天干在观线| 少妇视频一区二区| 亚洲国产精品视频| 精品国产xxx| 欧美久久久久中文字幕| 内射无码专区久久亚洲| 亚洲跨种族黑人xxx| 91精品专区| 欧美高清视频一区二区| 亚洲欧洲日本韩国| 成人在线一区二区| 久久成人福利| 亚洲一区在线免费| 亚洲小说欧美另类婷婷| 亚洲欧美另类动漫| 国产激情精品久久久第一区二区 | 亚洲欧洲av一区二区三区久久| 青青草原国产视频| 色婷婷综合久久久久中文一区二区| 国产乱码一区二区| 亚洲老头老太hd| 特级毛片在线| 国产成+人+综合+亚洲欧洲| 136国产福利精品导航网址应用| 日本不卡一区| 激情文学一区| 91pony九色| 久久蜜臀精品av| 久久精品国产亚洲AV无码麻豆| 欧美在线综合视频| 日韩一卡二卡在线| 久久国产加勒比精品无码| 男人最爱成人网| 国产精品一区二区三区不卡| 欧美日韩中字| 成人黄色片视频| 不卡视频在线观看| 欧美亚洲日本在线| 欧美日韩国产一区二区三区地区| 青梅竹马是消防员在线| 色综合男人天堂| 国产激情一区| 天天人人精品| 久久天堂成人| 日本一区二区在线观看视频| 综合色中文字幕| 国产精品成人无码| 亚洲美女黄色片| 岛国毛片av在线| 高清日韩一区| 亚洲大全视频| 欧美视频国产视频| 欧美国产欧美综合| 中文字幕一区二区三区四区欧美| 日韩av在线看| 亚洲v.com| 精品一区二区国产| 99亚洲伊人久久精品影院红桃| 手机看片国产精品| 亚洲日本在线视频观看| 亚洲天堂avav| 尤物yw午夜国产精品视频| 韩国美女久久| 欧美精品一区二区三区在线四季 | 日韩一区免费视频| 国内自拍欧美激情| 国产亚洲成av人片在线观黄桃| av动漫在线播放| 国产精品系列在线播放| 18岁成人毛片| 欧美成人精精品一区二区频| 青春草免费在线视频| 高清免费日韩| 夜夜爽av福利精品导航| 日本黄色片在线播放| 日韩欧美在线观看| 国产一区二区三区福利| 国产精品大陆在线观看| 日韩av免费大片| 制服丝袜中文字幕第一页| 自拍偷拍亚洲欧美日韩| 精品久久在线观看| 欧美精品电影在线| 欧美黑白配在线| 欧美国产日韩在线播放| 国产精品久久久久久久久免费丝袜| 在线观看免费高清视频| 日韩视频永久免费观看| 亚洲国产aⅴ精品一区二区| 久久av综合网| 久久精品夜色噜噜亚洲aⅴ| 中文字幕av网站| 欧美xxxx18国产| 国产精品极品国产中出| 久草精品在线播放| 国产精品久久久爽爽爽麻豆色哟哟| 国产乱码精品一区二区| 国a精品视频大全| 精品在线播放| 欧美国产日韩另类 | 久久先锋资源网| 中文字幕有码无码人妻av蜜桃| 欧美成人第一页| 亚洲老女人视频免费| 亚洲免费黄色网| 午夜精品久久久久久久| 成年人视频在线观看免费| 91色在线观看| 国产手机视频一区二区| 91无套直看片红桃在线观看| 欧美v亚洲v综合ⅴ国产v| 性感美女一区二区在线观看| 国产精品一区在线免费观看| 99久久国产免费看| 一级片aaaa| 91精品国产99| 国产精品国产一区| 给我看免费高清在线观看| 欧美剧情片在线观看| 国产激情视频在线看| 在线免费一区| www久久精品| av在线免费在线观看| 奇米4444一区二区三区| 午夜精品久久| 超碰人人人人人人人| 亚洲国产成人在线视频|