LinkedBlockingQueue與ArrayBlockingQueue簡要比較

LinkedBlockingQueue基于鏈表實現(xiàn)先紫,未指定容量時默認容量為Integer.MAX_VALUE,即無界阻塞隊列筹煮,節(jié)點動態(tài)創(chuàng)建遮精,節(jié)點出隊后可被GC,伸縮性較好寺谤;如果消費者速度慢于生產(chǎn)者速度仑鸥,可能造成內(nèi)存空間不足,建議手動設置隊列大小变屁。
采用“two lock queue”算法變體眼俊,雙鎖(ReentrantLock):takeLock、putLock粟关,允許讀寫并行疮胖,remove(e)和迭代器iterators需要獲取2個鎖。
LinkedBlockingQueue同步機制:


image.png

ArrayBlockingQueue底層基于數(shù)組闷板,創(chuàng)建時必須指定隊列大小澎灸,節(jié)點數(shù)量一開始就固定,“有界”
ArrayBlockingQueue入隊和出隊使用同一個lock(但數(shù)據(jù)讀寫操作已非常簡潔)遮晚,讀取和寫入操作無法并行性昭。
ArrayBlockingQueue 同步機制:


image.png

LinkedBlockingQueue使用雙鎖可并行讀寫,其吞吐量更高县遣。
ArrayBlockingQueue在插入或刪除元素時直接放入數(shù)組指定位置(putIndex糜颠、takeIndex),不會產(chǎn)生或銷毀任何額外的對象實例萧求;而LinkedBlockingQueue則會生成一個額外的Node對象其兴,在高效并發(fā)處理大量數(shù)據(jù)時,對GC的影響存在一定的區(qū)別夸政。
在大部分并發(fā)場景下元旬,LinkedBlockingQueue的吞吐量比ArrayBlockingQueue更好。

// linkedblockingqueue.java
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    // 這里為什么是 -1 這就是個標識成功守问、失敗的標志而已匀归。
    int c = -1;
    Node<E> node = new Node(e);
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    // 必須要獲取到 putLock 才可以進行插入操作
    putLock.lockInterruptibly();
    try {
        // 如果隊列滿,等待 notFull 的條件滿足耗帕。
        while (count.get() == capacity) {
            notFull.await();
        }
        // 入隊
        enqueue(node);
        // count 原子加 1朋譬,c 還是加 1 前的值
        c = count.getAndIncrement();
        // 如果這個元素入隊后,還有至少一個槽可以使用兴垦,調(diào)用 notFull.signal() 喚醒等待線程徙赢。
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        // 入隊后字柠,釋放掉 putLock
        putLock.unlock();
    }
    // 如果 c == 0,那么代表隊列在這個元素入隊前是空的(不包括head空節(jié)點)狡赐,
    // 那么所有的讀線程都在等待 notEmpty 這個條件窑业,等待喚醒,這里做一次喚醒操作
    if (c == 0)
        signalNotEmpty();
}

// linkedblockingqueue.java
public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    // 首先枕屉,需要獲取到 takeLock 才能進行出隊操作
    takeLock.lockInterruptibly();
    try {
        // 如果隊列為空常柄,等待 notEmpty 這個條件滿足再繼續(xù)執(zhí)行
        while (count.get() == 0) {
            notEmpty.await();
        }
        // 出隊
        x = dequeue();
        // count 進行原子減 1
        c = count.getAndDecrement();
        // 如果這次出隊后,隊列中至少還有一個元素搀擂,那么調(diào)用 notEmpty.signal() 喚醒其他的讀線程
        if (c > 1)
            notEmpty.signal();
    } finally {
        // 出隊后釋放掉 takeLock
        takeLock.unlock();
    }
    // 如果 c == capacity西潘,那么說明在這個 take 方法發(fā)生的時候,隊列是滿的
    // 既然出隊了一個哨颂,那么意味著隊列不滿了喷市,喚醒寫線程去寫
    if (c == capacity)
        signalNotFull();
    return x;
}

兩種不同的生產(chǎn)者消費者協(xié)調(diào)策略:
在ArrayBlockingQueue中,速率的調(diào)控是通過生產(chǎn)者喚醒消費者威恼,消費者喚醒生產(chǎn)者互相作用來實現(xiàn)的調(diào)控品姓。
由于signal是要先獲取到鎖才能調(diào)用的,在put里是獲取不到take鎖的箫措,只能在自己的方法里去signal自己的condition隊列

linkedblockingqueue出于性能考慮用了兩個鎖腹备,盡量讓兩邊各自獨立,所以在LinkedBlockingQueue中斤蔓,是生產(chǎn)者在隊列未滿的情況下喚醒生產(chǎn)者植酥,
也就是finally之前的 if (c + 1 < capacity) notFull.signal();,消費者在隊列不為空的時候喚醒消費者弦牡,對應的是if (c > 1) notEmpty.signal(); 但是存在兩種特殊情況: 1 假設隊列滿了惧互,生產(chǎn)者可能全部處于await狀態(tài),那么此時就需要消費者出隊后喚醒生產(chǎn)者喇伯。也就是take操作return之前的signalNotFull()

假設隊列為空,消費者可能全部處于await狀態(tài)拨与,那么此時就需要生產(chǎn)者生產(chǎn)之后喚醒消費者稻据,也就是put操作return之前的signalNotEmpty()

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市买喧,隨后出現(xiàn)的幾起案子捻悯,更是在濱河造成了極大的恐慌,老刑警劉巖淤毛,帶你破解...
    沈念sama閱讀 212,816評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件今缚,死亡現(xiàn)場離奇詭異,居然都是意外死亡低淡,警方通過查閱死者的電腦和手機姓言,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,729評論 3 385
  • 文/潘曉璐 我一進店門瞬项,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人何荚,你說我怎么就攤上這事囱淋。” “怎么了餐塘?”我有些...
    開封第一講書人閱讀 158,300評論 0 348
  • 文/不壞的土叔 我叫張陵妥衣,是天一觀的道長。 經(jīng)常有香客問我戒傻,道長税手,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,780評論 1 285
  • 正文 為了忘掉前任需纳,我火速辦了婚禮芦倒,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘候齿。我一直安慰自己熙暴,他們只是感情好,可當我...
    茶點故事閱讀 65,890評論 6 385
  • 文/花漫 我一把揭開白布慌盯。 她就那樣靜靜地躺著周霉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪亚皂。 梳的紋絲不亂的頭發(fā)上俱箱,一...
    開封第一講書人閱讀 50,084評論 1 291
  • 那天,我揣著相機與錄音灭必,去河邊找鬼狞谱。 笑死,一個胖子當著我的面吹牛禁漓,可吹牛的內(nèi)容都是我干的跟衅。 我是一名探鬼主播,決...
    沈念sama閱讀 39,151評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼播歼,長吁一口氣:“原來是場噩夢啊……” “哼伶跷!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起秘狞,我...
    開封第一講書人閱讀 37,912評論 0 268
  • 序言:老撾萬榮一對情侶失蹤叭莫,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后烁试,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雇初,經(jīng)...
    沈念sama閱讀 44,355評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,666評論 2 327
  • 正文 我和宋清朗相戀三年减响,在試婚紗的時候發(fā)現(xiàn)自己被綠了靖诗。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郭怪。...
    茶點故事閱讀 38,809評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖呻畸,靈堂內(nèi)的尸體忽然破棺而出移盆,到底是詐尸還是另有隱情,我是刑警寧澤伤为,帶...
    沈念sama閱讀 34,504評論 4 334
  • 正文 年R本政府宣布咒循,位于F島的核電站,受9級特大地震影響绞愚,放射性物質(zhì)發(fā)生泄漏叙甸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,150評論 3 317
  • 文/蒙蒙 一位衩、第九天 我趴在偏房一處隱蔽的房頂上張望裆蒸。 院中可真熱鬧,春花似錦糖驴、人聲如沸僚祷。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽辙谜。三九已至,卻和暖如春感昼,著一層夾襖步出監(jiān)牢的瞬間装哆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,121評論 1 267
  • 我被黑心中介騙來泰國打工定嗓, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蜕琴,地道東北人。 一個月前我還...
    沈念sama閱讀 46,628評論 2 362
  • 正文 我出身青樓宵溅,卻偏偏與公主長得像凌简,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子恃逻,可洞房花燭夜當晚...
    茶點故事閱讀 43,724評論 2 351

推薦閱讀更多精彩內(nèi)容