Java集合框架源碼研讀-ArrayBlockingQueue

今天我們來介紹一個(gè)BlockingQueue的實(shí)現(xiàn),ArrayBlockingQueue.

從其名字中,我們就能得知,首先,這是一個(gè)隊(duì)列,其次,這個(gè)隊(duì)列能夠被阻塞,最后,它的底層數(shù)據(jù)結(jié)構(gòu)是一個(gè)數(shù)組.

老規(guī)矩,我們還是先貼上來ArrayBlockingQueue的類注釋:

從類注釋中,我們可以發(fā)現(xiàn)幾點(diǎn)我們剛才沒有提到的:

  • 這個(gè)隊(duì)列會(huì)按照FIFO的順序來處理數(shù)據(jù)(這也是隊(duì)列的一個(gè)特性)
  • 新元素被插入到隊(duì)列的末尾,而要獲取的元素則位于隊(duì)列的首部.(這里說的隊(duì)列的末尾和隊(duì)列的首部只是一個(gè)邏輯概念,因?yàn)槠涞讓拥臄?shù)據(jù)結(jié)構(gòu)畢竟是一個(gè)數(shù)組)
  • 底層數(shù)據(jù)結(jié)構(gòu)數(shù)組的長度不可變
  • 向一個(gè)滿隊(duì)列執(zhí)行put()操作會(huì)導(dǎo)致線程阻塞,而向一個(gè)空隊(duì)列執(zhí)行take()操作,也會(huì)導(dǎo)致線程阻塞
  • 可以為生產(chǎn)者線程和消費(fèi)者線程指定一個(gè)公平策略,如果指定這樣一個(gè)策略,那么總是會(huì)讓等待時(shí)間最久的線程獲得數(shù)據(jù),或者插入數(shù)據(jù)
  • 默認(rèn)情況下,是沒有上述的公平策略的,即當(dāng)有多個(gè)消費(fèi)者在等待時(shí),隨機(jī)選擇一個(gè)線程讓其獲得數(shù)據(jù),對(duì)生產(chǎn)者也這樣
  • 公平策略有好處也有壞處,好處是能夠防止饑餓現(xiàn)象,壞處是會(huì)降低吞吐量.

ArrayBlockingQueue的內(nèi)部結(jié)構(gòu)

從上文中,我們也提到了,ArrayBlockingQueue的內(nèi)部的數(shù)據(jù)結(jié)構(gòu)是一個(gè)數(shù)組.

但是,僅僅一個(gè)數(shù)組,是肯定不夠的.

ArrayBlockingQueue中,還定義了這么幾種屬性:

  • takeIndex: 表示下次執(zhí)行take(),poll(),peek()或remove()操作時(shí)數(shù)據(jù)的位置
  • putIndex: 表示下次執(zhí)行put(), offer(), add()操作時(shí),數(shù)據(jù)的位置
  • count: 隊(duì)列中已經(jīng)存在的數(shù)據(jù)的個(gè)數(shù)

那么為什么需要takeIndex和putIndex這么兩個(gè)字段呢?在ArrayList的實(shí)現(xiàn)中,當(dāng)移除元素時(shí),會(huì)涉及到數(shù)組中,數(shù)據(jù)的移動(dòng),所以,進(jìn)行頻繁的數(shù)據(jù)移除操作,是不適合用ArrayList的.同理,由于BlockingQueue的主要用處就是插入數(shù)據(jù)以及刪除(讀取)數(shù)據(jù),如果每次刪除數(shù)據(jù)時(shí),都進(jìn)行數(shù)組中數(shù)據(jù)的移動(dòng),肯定是不適合的.所以,就用這么兩個(gè)指針,分別指向下次讀取數(shù)據(jù)時(shí)的位置,以及插入數(shù)據(jù)時(shí)的位置.

那么,你可能就有疑問了,既然不進(jìn)行數(shù)據(jù)的移動(dòng),而且數(shù)組的容量又是有限的,那么最后takeIndex和putIndex都指向數(shù)組的末尾?。@咋整?

我們可以參考循環(huán)鏈表的形式?。?/p>

當(dāng)takeIndex或者putIndex指向數(shù)組的末尾時(shí),就讓它指向數(shù)組的起始.因?yàn)閿?shù)據(jù)是按照FIFO的順序插入以及處理的,所以,數(shù)組中,takeIndex前面肯定是空的.所以,我們可以按照環(huán)形的方式處理.

這樣確實(shí)方便了數(shù)據(jù)的插入和刪除,那么我們?nèi)绾闻袛嚓?duì)列是否已經(jīng)滿了或者是空的呢?

我們不是有記錄了數(shù)組中數(shù)據(jù)的個(gè)數(shù)的count屬性嘛.我們可以通過這個(gè)屬性來判斷呀.

除了上面介紹的這幾個(gè)屬性,還有三個(gè)跟線程調(diào)度有關(guān)的屬性.

第一個(gè)是一個(gè)ReentrantLock,因?yàn)槲覀冃枰WCArrayBlockingQueue的每個(gè)操作都是線程安全的.

另外兩個(gè)分別是notEmptynotFull,它們的類型都是Condition,當(dāng)執(zhí)行數(shù)據(jù)讀取的操作比如poll(),如果隊(duì)列為空,那么就通過notEmpty讓當(dāng)前線程阻塞.notFull的用法類似.

ArrayBlockingQueue的相關(guān)操作

BlockingQueue中,定義了好幾個(gè)插入和訪問數(shù)據(jù)的操作,這幾個(gè)操作之間都有什么差別呢?就拿插入數(shù)據(jù)來說吧,有的操作是,如果隊(duì)列已滿,返回一個(gè)boolean值,有的是阻塞當(dāng)前線程,有的是拋出一個(gè)異常.具體的請(qǐng)參照下表:

BlockingQueue的使用場(chǎng)景

由上面的描述,相信你很容易就能看出,用BlockingQueue可以很方便的實(shí)現(xiàn)一個(gè)消息隊(duì)列.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一、多線程 說明下線程的狀態(tài) java中的線程一共有 5 種狀態(tài)。 NEW:這種情況指的是,通過 New 關(guān)鍵字創(chuàng)...
    Java旅行者閱讀 4,871評(píng)論 0 44
  • 譯序 本指南根據(jù) Jakob Jenkov 最新博客翻譯,請(qǐng)隨時(shí)關(guān)注博客更新:http://tutorials.j...
    高廣超閱讀 5,482評(píng)論 1 68
  • 星空下 月色比平常白 蚊蟲也比平時(shí)更忙碌 忙完了一天的老農(nóng) 站在地頭上吸煙 田里的稻谷剛收割 幾個(gè)小孩牽著自己的影...
    隔著玻璃親嘴閱讀 176評(píng)論 0 0
  • “堅(jiān)持就是勝利!”我從小就是聽這句話長大的。 但是我下定決心做的很多事都沒有堅(jiān)持下來,比如:我計(jì)劃...
    擼串串閱讀 480評(píng)論 3 3
  • 越害怕,越孤獨(dú) 越悲傷,越無助 霓虹燈照不亮眼淚 車來車往的馬路帶不走橙色的光 你本該在我的悲哀里長眠 卻在這繁世...
    何小盒閱讀 244評(píng)論 0 1

友情鏈接更多精彩內(nèi)容