java基礎(chǔ):java.util.concurrent.BlockingQueue

前言

在一次項(xiàng)目中冠桃,偶遇BlockingQueue命贴,特意查了下用法,使我對(duì)它有了強(qiáng)列的興趣食听,經(jīng)過一段時(shí)間的學(xué)習(xí)胸蛛,將其整理,用圖解的方式解釋樱报,方便理解葬项。

介紹

在新增的Concurrent包中,BlockingQueue很好的解決了多線程中迹蛤,如何高效安全“傳輸”數(shù)據(jù)的問題民珍。通過這些高效并且線程安全的隊(duì)列類,為我們快速搭建高質(zhì)量的多線程程序帶來極大的便利盗飒。圖(1_0.png)是其繼承關(guān)系嚷量,可以看出BlockingQueue是繼承Queue。

1_0.png

我們先看下BlockQueue的圖解逆趣,通過圖蝶溶,我們很容易理解,這是一個(gè)隊(duì)列基本圖宣渗,在圖中抖所,我們發(fā)現(xiàn)入隊(duì)有put、add落包、offer三個(gè)方法。出隊(duì)有poll摊唇、remove咐蝇、take三個(gè)方法,就是因?yàn)檫@幾個(gè)方法巷查,使得blockQueue功能很強(qiáng)大有序。

1_1.png

put、add岛请、offer 區(qū)別

  • put
    把Object加到BlockingQueue里,如果BlockQueue沒有空間,則調(diào)用此方法的線程被阻斷直到BlockingQueue里面有空間再繼續(xù).
  • add
    把Object加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則報(bào)異常
  • offer
    將Object加到BlockingQueue里,即如果BlockingQueue可以容納,則返回true,否則返回false.
    當(dāng)隊(duì)列滿了旭寿,put阻塞,等有了再加崇败,add直接報(bào)錯(cuò)盅称,offer返回狀態(tài)

poll肩祥、remove、take 區(qū)別

  • take
    取走BlockingQueue里排在首位的對(duì)象,若BlockingQueue為空,阻斷進(jìn)入等待狀態(tài)直到Blocking有新的對(duì)象被加入為止
  • remove
    取走BlockingQueue里排在首位的對(duì)象,若不能立即取出,則拋出異常
  • poll
    取走BlockingQueue里排在首位的對(duì)象,若不能立即取出,則可以等time參數(shù)規(guī)定的時(shí)間,
        取不到時(shí)返回null;
    當(dāng)隊(duì)列空了缩膝,take取不到就等混狠,remove就拋異常,poll就返回null

阻塞模型

  1. 當(dāng)隊(duì)列滿了疾层,再往隊(duì)列里put數(shù)據(jù)就會(huì)出現(xiàn)線程等待将饺,模型如下


    Paste_Image.png
  2. 當(dāng)隊(duì)列空了,再往隊(duì)列里take數(shù)據(jù)痛黎,就會(huì)出現(xiàn)線程等待予弧,模型如下

Paste_Image.png

實(shí)現(xiàn)了BlockingQueue的類

Paste_Image.png

我們常用的隊(duì)列就linkedBlockingQueue和ArrayBlockingQueue。

LinkedBlockingQueue 和 ArrayBlockingQueue

  • 區(qū)別
    我們區(qū)分下LinkedBlockingQueue和ArrayBlockingQueue湖饱,凡是linked打頭的都是內(nèi)部維護(hù)一個(gè)鏈表掖蛤,Array打頭的是維護(hù)一個(gè)數(shù)組,實(shí)現(xiàn)方式不一樣琉历,功能也有所區(qū)別坠七。
  • LinkedBlockingQueue是內(nèi)部維護(hù)一個(gè)鏈表,當(dāng)執(zhí)行put方法時(shí)旗笔,程序會(huì)先獲得一個(gè)重入鎖彪置,防止多線程同時(shí)操作產(chǎn)生數(shù)據(jù)不正確,然后后生成一個(gè)數(shù)據(jù)節(jié)點(diǎn)(Node)添加到鏈表的最后面蝇恶。如果隊(duì)列滿拳魁,則使用java.util.concurrent.locks.Condition的await()方法來阻塞繼續(xù)添加。
    這是put方法源碼:
    public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    int c = -1;
    final ReentrantLock putLock = this.putLock;
    final AtomicInteger count = this.count;
    putLock.lockInterruptibly();
    try {
    while (count.get() == capacity) {
    notFull.await();
    }
    enqueue(e);
    c = count.getAndIncrement();
    if (c + 1 < capacity)
    notFull.signal();
    } finally {
    putLock.unlock();
    }
    if (c == 0)
    signalNotEmpty();
    }
    take()取數(shù)據(jù)也用了await()方法撮弧,了解原理后潘懊,發(fā)現(xiàn)取數(shù)據(jù)時(shí)當(dāng)鏈表為空時(shí),就阻塞贿衍。
    這是take()方法源碼:
    public E take() throws InterruptedException {
    E x;
    int c = -1;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lockInterruptibly();
    try {
    while (count.get() == 0) {
    notEmpty.await();
    }
    x = dequeue();
    c = count.getAndDecrement();
    if (c > 1)
    notEmpty.signal();
    } finally {
    takeLock.unlock();
    }
    if (c == capacity)
    signalNotFull();
    return x;
    }
  • ArrayBlockingQueue是內(nèi)部維護(hù)一個(gè)數(shù)組授舟,當(dāng)執(zhí)行put方法時(shí),程序也會(huì)先獲得一個(gè)重入鎖贸辈,防止多純種同時(shí)操作數(shù)組释树,然后直接插入到數(shù)組上面,這里和linkedBlockingQueue有個(gè)區(qū)別就是不會(huì)產(chǎn)生一個(gè)新的對(duì)象節(jié)點(diǎn)擎淤,開銷上插入比LinkedBlockQueue節(jié)省空間奢啥。
    這是put方法源碼:
    public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    final E[] items = this.items;
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
    try {
    while (count == items.length)
    notFull.await();
    } catch (InterruptedException ie) {
    notFull.signal(); // propagate to non-interrupted thread
    throw ie;
    }
    insert(e);
    } finally {
    lock.unlock();
    }
    }
  • 總結(jié)

這兩個(gè)隊(duì)列的實(shí)現(xiàn)幾乎都是相似的,我們可以理解成對(duì)應(yīng)的數(shù)組和鏈表的實(shí)現(xiàn)嘴拢。并且是線程安全的桩盲,在特定場(chǎng)景中使用特定的實(shí)現(xiàn)類能保證高效和空間的合理性。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末席吴,一起剝皮案震驚了整個(gè)濱河市赌结,隨后出現(xiàn)的幾起案子捞蛋,更是在濱河造成了極大的恐慌,老刑警劉巖姑曙,帶你破解...
    沈念sama閱讀 217,406評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件襟交,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡伤靠,警方通過查閱死者的電腦和手機(jī)捣域,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來宴合,“玉大人焕梅,你說我怎么就攤上這事∝郧ⅲ” “怎么了贞言?”我有些...
    開封第一講書人閱讀 163,711評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長阀蒂。 經(jīng)常有香客問我该窗,道長,這世上最難降的妖魔是什么蚤霞? 我笑而不...
    開封第一講書人閱讀 58,380評(píng)論 1 293
  • 正文 為了忘掉前任酗失,我火速辦了婚禮,結(jié)果婚禮上昧绣,老公的妹妹穿的比我還像新娘规肴。我一直安慰自己,他們只是感情好夜畴,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,432評(píng)論 6 392
  • 文/花漫 我一把揭開白布拖刃。 她就那樣靜靜地躺著,像睡著了一般贪绘。 火紅的嫁衣襯著肌膚如雪兑牡。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,301評(píng)論 1 301
  • 那天税灌,我揣著相機(jī)與錄音均函,去河邊找鬼。 笑死垄琐,一個(gè)胖子當(dāng)著我的面吹牛边酒,可吹牛的內(nèi)容都是我干的经柴。 我是一名探鬼主播狸窘,決...
    沈念sama閱讀 40,145評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼坯认!你這毒婦竟也來了翻擒?” 一聲冷哼從身側(cè)響起氓涣,我...
    開封第一講書人閱讀 39,008評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎陋气,沒想到半個(gè)月后劳吠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,443評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡巩趁,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,649評(píng)論 3 334
  • 正文 我和宋清朗相戀三年痒玩,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片议慰。...
    茶點(diǎn)故事閱讀 39,795評(píng)論 1 347
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡蠢古,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出别凹,到底是詐尸還是另有隱情草讶,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評(píng)論 5 345
  • 正文 年R本政府宣布炉菲,位于F島的核電站堕战,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏拍霜。R本人自食惡果不足惜嘱丢,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,119評(píng)論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望沉御。 院中可真熱鬧屿讽,春花似錦、人聲如沸吠裆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽试疙。三九已至诵棵,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間祝旷,已是汗流浹背履澳。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留怀跛,地道東北人距贷。 一個(gè)月前我還...
    沈念sama閱讀 47,899評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像吻谋,于是被迫代替她去往敵國和親忠蝗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,724評(píng)論 2 354

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

  • layout: posttitle: 《Java并發(fā)編程的藝術(shù)》筆記categories: Javaexcerpt...
    xiaogmail閱讀 5,819評(píng)論 1 19
  • 一.線程安全性 線程安全是建立在對(duì)于對(duì)象狀態(tài)訪問操作進(jìn)行管理漓拾,特別是對(duì)共享的與可變的狀態(tài)的訪問 解釋下上面的話: ...
    黃大大吃不胖閱讀 842評(píng)論 0 3
  • 相關(guān)概念 面向?qū)ο蟮娜齻€(gè)特征 封裝,繼承,多態(tài).這個(gè)應(yīng)該是人人皆知.有時(shí)候也會(huì)加上抽象. 多態(tài)的好處 允許不同類對(duì)...
    東經(jīng)315度閱讀 1,940評(píng)論 0 8
  • java筆記第一天 == 和 equals ==比較的比較的是兩個(gè)變量的值是否相等阁最,對(duì)于引用型變量表示的是兩個(gè)變量...
    jmychou閱讀 1,497評(píng)論 0 3
  • 拉起窗簾 打開昨日的書簽 給窗前的草 澆點(diǎn)水 然后 看著它 笑上一整天 有時(shí)候 突然有點(diǎn)傷感 午后的輕眠 ...
    玩笑的熊閱讀 371評(píng)論 12 11