内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

java集合之ConcurrentLinkedQueue的示例代碼-創(chuàng)新互聯(lián)

這篇文章給大家分享的是有關(guān)java集合之ConcurrentLinkedQueue的示例代碼的內(nèi)容。小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,一起跟隨小編過來看看吧。

成都創(chuàng)新互聯(lián)公司主營平鄉(xiāng)網(wǎng)站建設(shè)的網(wǎng)絡(luò)公司,主營網(wǎng)站建設(shè)方案,手機(jī)APP定制開發(fā),平鄉(xiāng)h5微信小程序搭建,平鄉(xiāng)網(wǎng)站營銷推廣歡迎平鄉(xiāng)等地區(qū)企業(yè)咨詢

問題

(1)ConcurrentLinkedQueue是阻塞隊(duì)列嗎?

(2)ConcurrentLinkedQueue如何保證并發(fā)安全?

(3)ConcurrentLinkedQueue能用于線程池嗎?

簡介

ConcurrentLinkedQueue只實(shí)現(xiàn)了Queue接口,并沒有實(shí)現(xiàn)BlockingQueue接口,所以它不是阻塞隊(duì)列,也不能用于線程池中,但是它是線程安全的,可用于多線程環(huán)境中。


那么,它的線程安全又是如何實(shí)現(xiàn)的呢?讓我們一起來瞧一瞧。

源碼分析

主要屬性

// 鏈表頭節(jié)點(diǎn)
private transient volatile Node<E> head;
// 鏈表尾節(jié)點(diǎn)
private transient volatile Node<E> tail;

就這兩個(gè)主要屬性,一個(gè)頭節(jié)點(diǎn),一個(gè)尾節(jié)點(diǎn)。

主要內(nèi)部類

private static class Node<E> {
    volatile E item;
    volatile Node<E> next;
}

典型的單鏈表結(jié)構(gòu),非常純粹。

主要構(gòu)造方法

public ConcurrentLinkedQueue() {
    // 初始化頭尾節(jié)點(diǎn)
    head = tail = new Node<E>(null);
}

public ConcurrentLinkedQueue(Collection<? extends E> c) {
    Node<E> h = null, t = null;
    // 遍歷c,并把它元素全部添加到單鏈表中
    for (E e : c) {
        checkNotNull(e);
        Node<E> newNode = new Node<E>(e);
        if (h == null)
            h = t = newNode;
        else {
            t.lazySetNext(newNode);
            t = newNode;
        }
    }
    if (h == null)
        h = t = new Node<E>(null);
    head = h;
    tail = t;
}

這兩個(gè)構(gòu)造方法也很簡單,可以看到這是一個(gè)×××的單鏈表實(shí)現(xiàn)的隊(duì)列。

入隊(duì)

因?yàn)樗皇亲枞?duì)列,所以只有兩個(gè)入隊(duì)的方法,add(e)和offer(e)。

因?yàn)槭恰痢痢陵?duì)列,所以add(e)方法也不用拋出異常了。

public boolean add(E e) {
    return offer(e);
}

public boolean offer(E e) {
    // 不能添加空元素
    checkNotNull(e);
    // 新節(jié)點(diǎn)
    final Node<E> newNode = new Node<E>(e);

    // 入隊(duì)到鏈表尾
    for (Node<E> t = tail, p = t;;) {
        Node<E> q = p.next;
        // 如果沒有next,說明到鏈表尾部了,就入隊(duì)
        if (q == null) {
            // CAS更新p的next為新節(jié)點(diǎn)
            // 如果成功了,就返回true
            // 如果不成功就重新取next重新嘗試
            if (p.casNext(null, newNode)) {
                // 如果p不等于t,說明有其它線程先一步更新tail
                // 也就不會走到q==null這個(gè)分支了
                // p取到的可能是t后面的值
                // 把tail原子更新為新節(jié)點(diǎn)
                if (p != t) // hop two nodes at a time
                    casTail(t, newNode);  // Failure is OK.
                // 返回入隊(duì)成功
                return true;
            }
        }
        else if (p == q)
            // 如果p的next等于p,說明p已經(jīng)被刪除了(已經(jīng)出隊(duì)了)
            // 重新設(shè)置p的值
            p = (t != (t = tail)) ? t : head;
        else
            // t后面還有值,重新設(shè)置p的值
            p = (p != t && t != (t = tail)) ? t : q;
    }
}

入隊(duì)整個(gè)流程還是比較清晰的,這里有個(gè)前提是出隊(duì)時(shí)會把出隊(duì)的那個(gè)節(jié)點(diǎn)的next設(shè)置為節(jié)點(diǎn)本身。

(1)定位到鏈表尾部,嘗試把新節(jié)點(diǎn)放到后面;

(2)如果尾部變化了,則重新獲取尾部,再重試;

出隊(duì)

因?yàn)樗皇亲枞?duì)列,所以只有兩個(gè)出隊(duì)的方法,remove()和poll()。

public E remove() {
    E x = poll();
    if (x != null)
        return x;
    else
        throw new NoSuchElementException();
}

public E poll() {
    restartFromHead:
    for (;;) {
        // 嘗試彈出鏈表的頭節(jié)點(diǎn)
        for (Node<E> h = head, p = h, q;;) {
            E item = p.item;
            // 如果節(jié)點(diǎn)的值不為空,并且將其更新為null成功了
            if (item != null && p.casItem(item, null)) {
                // 如果頭節(jié)點(diǎn)變了,則不會走到這個(gè)分支
                // 會先走下面的分支拿到新的頭節(jié)點(diǎn)
                // 這時(shí)候p就不等于h了,就更新頭節(jié)點(diǎn)
                // 在updateHead()中會把head更新為新節(jié)點(diǎn)
                // 并讓head的next指向其自己
                if (p != h) // hop two nodes at a time
                    updateHead(h, ((q = p.next) != null) ? q : p);
                // 上面的casItem()成功,就可以返回出隊(duì)的元素了
                return item;
            }
            // 下面三個(gè)分支說明頭節(jié)點(diǎn)變了
            // 且p的item肯定為null
            else if ((q = p.next) == null) {
                // 如果p的next為空,說明隊(duì)列中沒有元素了
                // 更新h為p,也就是空元素的節(jié)點(diǎn)
                updateHead(h, p);
                // 返回null
                return null;
            }
            else if (p == q)
                // 如果p等于p的next,說明p已經(jīng)出隊(duì)了,重試
                continue restartFromHead;
            else
                // 將p設(shè)置為p的next
                p = q;
        }
    }
}
// 更新頭節(jié)點(diǎn)的方法
final void updateHead(Node<E> h, Node<E> p) {
    // 原子更新h為p成功后,延遲更新h的next為它自己
    // 這里用延遲更新是安全的,因?yàn)閔ead節(jié)點(diǎn)已經(jīng)變了
    // 只要入隊(duì)出隊(duì)的時(shí)候檢查head有沒有變化就行了,跟它的next關(guān)系不大
    if (h != p && casHead(h, p))
        h.lazySetNext(h);
}

出隊(duì)的整個(gè)邏輯也是比較清晰的:

(1)定位到頭節(jié)點(diǎn),嘗試更新其值為null;

(2)如果成功了,就成功出隊(duì);

(3)如果失敗或者頭節(jié)點(diǎn)變化了,就重新尋找頭節(jié)點(diǎn),并重試;

(4)整個(gè)出隊(duì)過程沒有一點(diǎn)阻塞相關(guān)的代碼,所以出隊(duì)的時(shí)候不會阻塞線程,沒找到元素就返回null;

感謝各位的閱讀!關(guān)于“java集合之ConcurrentLinkedQueue的示例代碼”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,讓大家可以學(xué)到更多知識,如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!

另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價(jià)比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。

本文標(biāo)題:java集合之ConcurrentLinkedQueue的示例代碼-創(chuàng)新互聯(lián)
文章URL:http://www.rwnh.cn/article12/hddgc.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供營銷型網(wǎng)站建設(shè)網(wǎng)站設(shè)計(jì)公司、手機(jī)網(wǎng)站建設(shè)搜索引擎優(yōu)化、用戶體驗(yàn)微信公眾號

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)

h5響應(yīng)式網(wǎng)站建設(shè)
四会市| 东乌珠穆沁旗| 西畴县| 固原市| 公主岭市| 华阴市| 汉川市| 齐齐哈尔市| 宁化县| 镇江市| 涟水县| 五原县| 娱乐| 偏关县| 错那县| 新巴尔虎左旗| 周口市| 新津县| 尼勒克县| 闽清县| 永胜县| 登封市| 青岛市| 固始县| 大庆市| 思茅市| 磐安县| 塔城市| 同德县| 麻江县| 怀柔区| 青冈县| 刚察县| 竹北市| 泰宁县| 公主岭市| 遂川县| 黄梅县| 鄄城县| 涿鹿县| 保靖县|