日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不

當(dāng)前位置:首頁 > 科技  > 軟件

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

來源: 責(zé)編: 時(shí)間:2024-02-04 08:59:25 265觀看
導(dǎo)讀引言前面文章我們講解了ArrayBlockingQueue和LinkedBlockingQueue源碼,這篇文章開始講解SynchronousQueue源碼。從名字上就能看到ArrayBlockingQueue是基于數(shù)組實(shí)現(xiàn)的,而LinkedBlockingQueue是基于鏈表實(shí)現(xiàn),而Synchronou

引言

前面文章我們講解了ArrayBlockingQueue和LinkedBlockingQueue源碼,這篇文章開始講解SynchronousQueue源碼。從名字上就能看到ArrayBlockingQueue是基于數(shù)組實(shí)現(xiàn)的,而LinkedBlockingQueue是基于鏈表實(shí)現(xiàn),而SynchronousQueue是基于什么數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,看不來。r1s28資訊網(wǎng)——每日最新資訊28at.com

無論是ArrayBlockingQueue還是LinkedBlockingQueue都是起到緩沖隊(duì)列的作用,當(dāng)消費(fèi)者的消費(fèi)速度跟不上時(shí),任務(wù)就在隊(duì)列中堆積,需要等待消費(fèi)者慢慢消費(fèi)。r1s28資訊網(wǎng)——每日最新資訊28at.com

如果我們想要自己的任務(wù)快速執(zhí)行,不要積壓在隊(duì)列中,該怎么辦? 今天的主角SynchronousQueue就派上用場(chǎng)了。r1s28資訊網(wǎng)——每日最新資訊28at.com

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

由于SynchronousQueue實(shí)現(xiàn)了BlockingQueue接口,而BlockingQueue接口中定義了幾組放數(shù)據(jù)和取數(shù)據(jù)的方法,來滿足不同的場(chǎng)景。r1s28資訊網(wǎng)——每日最新資訊28at.com

操作
r1s28資訊網(wǎng)——每日最新資訊28at.com

拋出異常
r1s28資訊網(wǎng)——每日最新資訊28at.com

返回特定值
r1s28資訊網(wǎng)——每日最新資訊28at.com

一直阻塞
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞指定時(shí)間
r1s28資訊網(wǎng)——每日最新資訊28at.com

放數(shù)據(jù)
r1s28資訊網(wǎng)——每日最新資訊28at.com

add()
r1s28資訊網(wǎng)——每日最新資訊28at.com

offer()
r1s28資訊網(wǎng)——每日最新資訊28at.com

put()
r1s28資訊網(wǎng)——每日最新資訊28at.com

offer(e, time, unit)
r1s28資訊網(wǎng)——每日最新資訊28at.com

取數(shù)據(jù)(同時(shí)刪除數(shù)據(jù))
r1s28資訊網(wǎng)——每日最新資訊28at.com

remove()
r1s28資訊網(wǎng)——每日最新資訊28at.com

poll()
r1s28資訊網(wǎng)——每日最新資訊28at.com

take()
r1s28資訊網(wǎng)——每日最新資訊28at.com

poll(time, unit)
r1s28資訊網(wǎng)——每日最新資訊28at.com

取數(shù)據(jù)(不刪除)
r1s28資訊網(wǎng)——每日最新資訊28at.com

element()
r1s28資訊網(wǎng)——每日最新資訊28at.com

peek()
r1s28資訊網(wǎng)——每日最新資訊28at.com

不支持
r1s28資訊網(wǎng)——每日最新資訊28at.com

不支持
r1s28資訊網(wǎng)——每日最新資訊28at.com

SynchronousQueue也會(huì)有針對(duì)這幾組放數(shù)據(jù)和取數(shù)據(jù)方法的具體實(shí)現(xiàn)。r1s28資訊網(wǎng)——每日最新資訊28at.com

Java線程池中的帶緩存的線程池就是基于SynchronousQueue實(shí)現(xiàn)的:r1s28資訊網(wǎng)——每日最新資訊28at.com

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

對(duì)應(yīng)的源碼實(shí)現(xiàn):r1s28資訊網(wǎng)——每日最新資訊28at.com

// 底層使用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類里面有哪些屬性:r1s28資訊網(wǎng)——每日最新資訊28at.com

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)。r1s28資訊網(wǎng)——每日最新資訊28at.com

初始化

SynchronousQueue常用的初始化方法有兩個(gè):r1s28資訊網(wǎng)——每日最新資訊28at.com

  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):r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 無參構(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)造方法可以指定使用公平策略。操作策略:r1s28資訊網(wǎng)——每日最新資訊28at.com

  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)模式有以下三種:r1s28資訊網(wǎng)——每日最新資訊28at.com

類型值
r1s28資訊網(wǎng)——每日最新資訊28at.com

類型描述
r1s28資訊網(wǎng)——每日最新資訊28at.com

作用
r1s28資訊網(wǎng)——每日最新資訊28at.com

0
r1s28資訊網(wǎng)——每日最新資訊28at.com

REQUEST
r1s28資訊網(wǎng)——每日最新資訊28at.com

表示取數(shù)據(jù)
r1s28資訊網(wǎng)——每日最新資訊28at.com

1
r1s28資訊網(wǎng)——每日最新資訊28at.com

DATA
r1s28資訊網(wǎng)——每日最新資訊28at.com

表示放數(shù)據(jù)
r1s28資訊網(wǎng)——每日最新資訊28at.com

2
r1s28資訊網(wǎng)——每日最新資訊28at.com

FULFILLING
r1s28資訊網(wǎng)——每日最新資訊28at.com

表示正在執(zhí)行中(比如取數(shù)據(jù)的線程正在匹配放數(shù)據(jù)的線程)
r1s28資訊網(wǎng)——每日最新資訊28at.com

圖片圖片r1s28資訊網(wǎng)——每日最新資訊28at.com

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

transfer()方法中,把放數(shù)據(jù)和取數(shù)據(jù)的邏輯耦合在一塊了,邏輯有點(diǎn)繞,不過核心邏輯就四點(diǎn),把握住就能豁然開朗。其實(shí)就是從棧頂壓入,從棧頂彈出。r1s28資訊網(wǎng)——每日最新資訊28at.com

詳細(xì)流程如下:r1s28資訊網(wǎng)——每日最新資訊28at.com

  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步,掛起線程的代碼邏輯: 核心邏輯就兩條:r1s28資訊網(wǎng)——每日最新資訊28at.com

  • 第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)。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 匹配節(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)。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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ì)流程如下:r1s28資訊網(wǎng)——每日最新資訊28at.com

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

看完了底層源碼,再看一下上層包裝好的工具方法。r1s28資訊網(wǎng)——每日最新資訊28at.com

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

放數(shù)據(jù)的方法有四個(gè):r1s28資訊網(wǎng)——每日最新資訊28at.com

操作
r1s28資訊網(wǎng)——每日最新資訊28at.com

拋出異常
r1s28資訊網(wǎng)——每日最新資訊28at.com

返回特定值
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞一段時(shí)間
r1s28資訊網(wǎng)——每日最新資訊28at.com

放數(shù)據(jù)
r1s28資訊網(wǎng)——每日最新資訊28at.com

add()
r1s28資訊網(wǎng)——每日最新資訊28at.com

offer()
r1s28資訊網(wǎng)——每日最新資訊28at.com

put()
r1s28資訊網(wǎng)——每日最新資訊28at.com

offer(e, time, unit)
r1s28資訊網(wǎng)——每日最新資訊28at.com

offer方法源碼

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

/** * 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è)添加元素方法源碼:r1s28資訊網(wǎng)——每日最新資訊28at.com

add方法源碼

如果沒有匹配到合適的節(jié)點(diǎn),add()方法會(huì)拋出異常,底層基于offer()實(shí)現(xiàn)。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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ù),才能添加成功。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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è):r1s28資訊網(wǎng)——每日最新資訊28at.com

操作
r1s28資訊網(wǎng)——每日最新資訊28at.com

拋出異常
r1s28資訊網(wǎng)——每日最新資訊28at.com

返回特定值
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞一段時(shí)間
r1s28資訊網(wǎng)——每日最新資訊28at.com

取數(shù)據(jù)(同時(shí)刪除數(shù)據(jù))
r1s28資訊網(wǎng)——每日最新資訊28at.com

remove()
r1s28資訊網(wǎng)——每日最新資訊28at.com

poll()
r1s28資訊網(wǎng)——每日最新資訊28at.com

take()
r1s28資訊網(wǎng)——每日最新資訊28at.com

poll(time, unit)
r1s28資訊網(wǎng)——每日最新資訊28at.com

poll方法源碼

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

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

remove方法源碼

再看一下remove()方法源碼,如果沒有匹配到合適的節(jié)點(diǎn),remove()會(huì)拋出異常。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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()方法就一直阻塞,直到被喚醒。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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ù)。r1s28資訊網(wǎng)——每日最新資訊28at.com

操作
r1s28資訊網(wǎng)——每日最新資訊28at.com

拋出異常
r1s28資訊網(wǎng)——每日最新資訊28at.com

返回特定值
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞
r1s28資訊網(wǎng)——每日最新資訊28at.com

阻塞一段時(shí)間
r1s28資訊網(wǎng)——每日最新資訊28at.com

取數(shù)據(jù)(不刪除)
r1s28資訊網(wǎng)——每日最新資訊28at.com

element()
r1s28資訊網(wǎng)——每日最新資訊28at.com

peek()
r1s28資訊網(wǎng)——每日最新資訊28at.com

不支持
r1s28資訊網(wǎng)——每日最新資訊28at.com

不支持
r1s28資訊網(wǎng)——每日最新資訊28at.com

peek方法源碼

先看一下peek()方法源碼,直接返回null,SynchronousQueue不支持這種操作。r1s28資訊網(wǎng)——每日最新資訊28at.com

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

element方法源碼

再看一下element()方法源碼,底層調(diào)用的也是peek()方法,也是不支持這種操作。r1s28資訊網(wǎng)——每日最新資訊28at.com

/** * 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):r1s28資訊網(wǎng)——每日最新資訊28at.com

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

本文鏈接:http://m.www897cc.com/showinfo-26-72426-0.html沒研究過SynchronousQueue源碼,就別寫精通線程池

聲明:本網(wǎng)頁內(nèi)容旨在傳播知識(shí),若有侵權(quán)等問題請(qǐng)及時(shí)與本網(wǎng)聯(lián)系,我們將在第一時(shí)間刪除處理。郵件:2376512515@qq.com

上一篇: Spring Boot + Nacos 實(shí)現(xiàn)了一個(gè)動(dòng)態(tài)化線程池,非常實(shí)用!

下一篇: Python開發(fā)者的必備知識(shí):內(nèi)存管理與垃圾回收

標(biāo)簽:
  • 熱門焦點(diǎn)
Top 日韩成人免费在线_国产成人一二_精品国产免费人成电影在线观..._日本一区二区三区久久久久久久久不
黄色一区二区在线| 中文一区在线| 一区二区三区在线观看欧美| 正在播放亚洲一区| 极品少妇一区二区三区| 国产精品久久久久一区二区| 99ri日韩精品视频| 国产精品自拍小视频| 欧美成人精品在线观看| 亚洲天堂偷拍| 欧美日韩国产影院| 国产主播一区| 日韩一级免费观看| 亚洲一区二区三区乱码aⅴ蜜桃女| 这里只有精品电影| 久久一区欧美| 国产精品一级二级三级| 亚洲精品一区二区三区不| 久热re这里精品视频在线6| 99精品国产在热久久婷婷| 在线看一区二区| 亚洲剧情一区二区| 久久精品国产第一区二区三区最新章节 | 欧美一级大片在线免费观看| 久久久五月婷婷| 欧美日韩免费观看中文| 蜜臀av一级做a爰片久久| 欧美午夜片在线观看| 狠狠色狠色综合曰曰| 一本大道av伊人久久综合| 久久久国产视频91| 国产精品盗摄一区二区三区| 伊人精品成人久久综合软件| 亚洲一区免费视频| 欧美成人网在线| 国产日韩精品在线| 一本一本久久a久久精品综合妖精 一本一本久久a久久精品综合麻豆 | 亚洲午夜激情在线| 麻豆av一区二区三区| 国产欧美日韩综合精品二区| 99re6这里只有精品视频在线观看| 久久久精品一区二区三区| 欧美偷拍另类| 亚洲青色在线| 久久婷婷久久| 国产伦精品一区二区三区| 日韩一级免费| 欧美国产日本高清在线| 国内精品久久久久久久影视麻豆| 亚洲一区二区三区在线| 欧美猛交免费看| 在线看视频不卡| 久久精品国产亚洲一区二区三区| 国产精品久久久久久五月尺| 日韩午夜黄色| 欧美电影在线| 亚洲国产精品视频| 久久视频在线免费观看| 国产私拍一区| 亚洲欧美激情精品一区二区| 欧美日韩国产探花| 亚洲日韩欧美视频一区| 麻豆精品在线播放| 精品999成人| 久久精品国产免费观看| 国产欧美一区视频| 午夜在线精品偷拍| 国产精品亚发布| 亚洲免费在线视频| 国产精品久久久久7777婷婷| 一区二区三区免费观看| 欧美日韩精品中文字幕| 日韩一级精品视频在线观看| 欧美韩日一区| 亚洲精选成人| 欧美精品七区| 日韩天天综合| 欧美日韩网站| 一区二区三区日韩精品| 欧美视频三区在线播放| 99精品视频免费| 欧美日韩视频专区在线播放| 日韩视频一区二区| 欧美日韩免费看| 一本色道综合亚洲| 欧美视频日韩视频在线观看| 亚洲视频在线观看网站| 国产精品久久久久三级| 午夜亚洲性色福利视频| 国产日韩在线看| 久久精品中文字幕免费mv| 一区二区视频免费在线观看 | 国产精品99一区二区| 亚洲嫩草精品久久| 国产亚洲精品久久久| 久久网站热最新地址| 精品电影在线观看| 欧美不卡视频| av不卡免费看| 国产精品一二一区| 久久精品国产第一区二区三区最新章节 | 欧美成人国产| 亚洲精品自在久久| 欧美网站在线| 午夜久久美女| 精品不卡在线| 欧美精品1区2区| 亚洲天堂激情| 国产一区清纯| 牛人盗摄一区二区三区视频| 99天天综合性| 国产欧美在线看| 老司机久久99久久精品播放免费 | 国产亚洲精品aa午夜观看| 久久久视频精品| 亚洲日本免费| 国产精品日日摸夜夜添夜夜av| 欧美专区福利在线| 亚洲国产日韩在线| 欧美视频二区36p| 久久精品国产99| 亚洲夫妻自拍| 国产精品久久影院| 毛片av中文字幕一区二区| 一区二区电影免费观看| 国产一级久久| 欧美精品一区二区视频| 午夜精品久久久久久99热| 有坂深雪在线一区| 欧美日韩在线三区| 久久久精品一区二区三区| 99热精品在线| 黑人巨大精品欧美一区二区小视频 | 美女网站久久| 亚洲香蕉网站| 在线观看av一区| 国产精品xxxav免费视频| 久久久精品性| 亚洲一区二区三区在线看 | 久久精品国产99| 亚洲视频欧美视频| 亚洲福利精品| 欧美激情一区在线观看| 欧美一区二区视频97| 亚洲免费精彩视频| 国内精品写真在线观看| 欧美午夜免费电影| 男女精品网站| 小辣椒精品导航| 99精品国产99久久久久久福利| 狠狠综合久久av一区二区老牛| 欧美三级电影大全| 欧美xart系列高清| 欧美中在线观看| 在线亚洲一区| 亚洲欧洲精品一区二区三区不卡| 国产精品一区二区久激情瑜伽| 欧美国产日产韩国视频| 久久久久国产精品厨房| 亚洲尤物在线视频观看| 亚洲精品自在在线观看| 伊人男人综合视频网| 国产伦精品一区二区三区高清版 | 久久在线视频在线| 亚洲欧美日韩国产成人| 日韩天堂在线观看| 亚洲国产一区在线观看| 国模私拍一区二区三区| 国产精品乱码久久久久久| 欧美久久精品午夜青青大伊人| 久久免费国产| 欧美在线视频免费| 亚洲欧美日韩国产综合精品二区| 99精品视频免费| 亚洲精品欧美在线| 在线免费日韩片| 黄色精品一区二区| 国产女人水真多18毛片18精品视频| 欧美日本精品| 欧美高清视频在线| 毛片一区二区| 久久综合精品一区| 久久久久久**毛片大全| 欧美在线啊v一区| 午夜视频在线观看一区二区| 亚洲一区二区三区久久| 亚洲一区制服诱惑| 亚洲午夜精品视频| 亚洲无线观看| 亚洲午夜国产成人av电影男同| 99精品视频一区| 夜久久久久久| 9色精品在线| 一区二区三区久久精品| 在线视频精品一区| 中日韩高清电影网| 中文有码久久| 亚洲新中文字幕| 亚洲免费在线精品一区| 亚洲女同在线| 欧美一级在线播放| 久久精品国产精品亚洲| 久久久91精品国产一区二区三区 | 狠狠做深爱婷婷久久综合一区|