JAVA中的阻塞隊列和非阻塞隊列

隊列是一種數(shù)據(jù)結(jié)構(gòu)禽炬,它有兩個基本操作:在隊列尾部加入元素和從隊列頭部移除元素。在我們?nèi)粘i_發(fā)中蟹瘾,經(jīng)常用來并發(fā)操作數(shù)據(jù)圾浅。java包中有一些應用比較廣泛的特殊隊列:一種是以ConcurrentLinkedQueue為代表的非阻塞隊列;另一種是以BlockingQueue接口為代表的阻塞隊列憾朴。通過這兩種隊列狸捕,我們保證了多線程操作數(shù)據(jù)的安全性。


java集合中的Queue繼承collection接口众雷,Dueue灸拍、LinkedList、PriorityQueue砾省、BlockingQueue等類都實現(xiàn)了它鸡岗。
阻塞隊列
阻塞隊列是一個支持兩個附加操作的隊列:1)在隊列為空時,獲取元素的線程會等待隊列變?yōu)榉强眨?)當隊列滿時编兄,存儲元素的線程會等待隊列可用轩性。因此,當一個線程試圖對一個已經(jīng)滿了的隊列進行入隊列操作時狠鸳,它將會被堵塞揣苏,除非有另一個線程做了出隊列的操作;同樣碰煌,當一個線程試圖對一個空隊列進行出隊列操作時舒岸,它將會被阻塞,除非有另外一個線程進行了入隊列的操作芦圾。
常見的阻塞隊列應用就是生產(chǎn)者消費者模式蛾派。生產(chǎn)者把數(shù)據(jù)放到隊列,如果隊列滿了个少,就會阻塞此操作洪乍,直到消費者消費,如果隊列中數(shù)據(jù)被消費完夜焦,那么消費者被阻塞壳澳,直到生產(chǎn)者生產(chǎn)。
在java包"java.util.concurrent"中茫经,提供六個實現(xiàn)了"BlockingQueue"接口的阻塞隊列巷波。分別是ArrayBlockingQueue萎津、LinkedBlockingQueue、PriorityBlockingQueue抹镊、DelayQueue锉屈、SynchronousQueue和LinkedBlockingDeque。實質(zhì)上阻塞隊列是一種特殊的FIFO數(shù)據(jù)結(jié)構(gòu)垮耳,它不是立即從隊列中添加或刪除元素颈渊,而是等到有空間或者元素可用的時候才操作。下面分析下每種阻塞隊列的實現(xiàn)方式和應用場景终佛。
ArrayBlockingQueue
用數(shù)組實現(xiàn)的有界阻塞隊列俊嗽,默認情況下不保證線程公平的訪問隊列(按照阻塞的先后順序訪問隊列),隊列可用的時候铃彰,阻塞的線程都可以爭奪隊列的訪問資格绍豁,當然也可以使用以下的構(gòu)造方法創(chuàng)建一個公平的阻塞隊列。ArrayBlockingQueue<String> blockingQueue2 = new ArrayBlockingQueue<>(10, true)豌研。(其實就是通過將ReentrantLock設(shè)置為true來 達到這種公平性的:即等待時間最長的線程會先操作)妹田。用ReentrantLock condition 實現(xiàn)阻塞。
有界就是隊列的長度有限制鹃共,例如數(shù)組隊列鬼佣,在構(gòu)建的時候就指定了長度。無界就是可以無限地添加霜浴。
LinkedBlockingQueue
基于鏈表實現(xiàn)的有界阻塞隊列晶衷。此隊列的默認和最大長度為Integer.MAX_VALUE。此隊列按照先進先出的原則對元素進行排序阴孟。這個隊列的實現(xiàn)原理和ArrayBlockingQueue實現(xiàn)基本相同晌纫。也是采用ReentrantLock 控制并發(fā),不同的是它使用兩個獨占鎖來控制消費和生產(chǎn)永丝。即用takeLock和putlock,這樣的好處是消費者和生產(chǎn)者可以并發(fā)執(zhí)行锹漱,對吞吐量有提升。
PriorityBlockingQueue
PriorityBlockingQueue是一個帶優(yōu)先級的隊列慕嚷,而不是先進先出隊列哥牍。元素按優(yōu)先級順序被移除,該隊列也沒有上限(PriorityBlockingQueue是對 PriorityQueue的再次包裝喝检,是基于堆數(shù)據(jù)結(jié)構(gòu)的嗅辣,而PriorityQueue是沒有容量限制的,與ArrayList一樣挠说,所以在優(yōu)先阻塞 隊列上put時是不會受阻的澡谭。雖然此隊列邏輯上是無界的,但是由于資源被耗盡损俭,所以試圖執(zhí)行添加操作可能會導致 OutOfMemoryError)蛙奖,但是如果隊列為空潘酗,那么取元素的操作take就會阻塞,所以它的檢索操作take是受阻的外永。也是用ReentrantLock控制并發(fā)崎脉。
DelayQueue
DelayQueue是在PriorityQueue基礎(chǔ)上實現(xiàn)的,底層也是數(shù)組構(gòu)造方法伯顶,是一個存放Delayed 元素的無界阻塞隊列,只有在延遲期滿時才能從中提取元素骆膝。該隊列的頭部是延遲期滿后保存時間最長的 Delayed 元素祭衩。如果延遲都還沒有期滿,則隊列沒有頭部阅签,并且poll將返回null掐暮。當一個元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一個小于或等于零的值時,則出現(xiàn)期滿政钟,poll就移除這個元素了路克。此隊列不允許使用 null 元素。
SynchronousQueue
一個沒有容量的隊列 养交,不會存儲數(shù)據(jù)精算,每執(zhí)行一次put就要執(zhí)行一次take,否則就會阻塞碎连。未使用鎖灰羽。通過cas實現(xiàn),吞吐量異常高鱼辙。內(nèi)部采用的就是ArrayBlockingQueue的阻塞隊列廉嚼,所以在功能上完全可以用ArrayBlockingQueue替換,但是SynchronousQueue是輕量級的倒戏,SynchronousQueue不具有任何內(nèi)部容量怠噪,我們可以用來在線程間安全的交換單一元素。所以功能比較單一杜跷,優(yōu)勢就在于輕量傍念。
LinkedBlockingDeque
LinkedBlockingDeque是雙向鏈表實現(xiàn)的雙向并發(fā)阻塞隊列。該阻塞隊列同時支持FIFO和FILO兩種操作方式葱椭,即可以從隊列的頭和尾同時操作(插入/刪除)捂寿;并且,該阻塞隊列是支持線程安全孵运,當多線程競爭同一個資源時秦陋,某線程獲取到該資源之后,其它線程需要阻塞等待治笨。此外驳概,LinkedBlockingDeque還是可選容量的(防止過度膨脹)赤嚼,即可以指定隊列的容量。如果不指定顺又,默認容量大小等于Integer.MAX_VALUE更卒。
非阻塞隊列
基于鎖的算法會帶來一些活躍度失敗的風險。如果線程在持有鎖的時候因為阻塞I/O稚照、頁面錯誤蹂空、或其他原因發(fā)生延遲,很可能所有的線程都不能工作了果录。一個線程的失敗或掛起不應該影響其他線程的失敗或掛起上枕,這樣的算法稱為非阻塞算法;如果算法的每一個步驟中都有一些線程能夠繼續(xù)執(zhí)行弱恒,那么這樣的算法稱為鎖自由(lock-free)算法辨萍。在線程間使用CAS進行協(xié)調(diào),這樣的算法如果能構(gòu)建正確的話返弹,它既是非阻塞的锈玉,又是鎖自由的。java中提供了基于CAS非阻塞算法實現(xiàn)的隊列义起,比較有代表性的有ConcurrentLinkedQueue和LinkedTransferQueue拉背,它們的性能一般比阻塞隊列的好。
ConcurrentLinkedQueue
ConcurrentLinkedQueue是一個基于鏈表的無界線程安全隊列并扇,它采用先進先出的規(guī)則對節(jié)點進行排序去团,當我們添加一個元素的時候,它會添加到隊列的尾部穷蛹;當我們獲取一個元素時土陪,它會返回隊列頭部的元素。ConcurrentLinkedQueue的線程安全是通過其插入肴熏、刪除時采取CAS操作來保證的鬼雀。由于使用CAS沒有使用鎖,所以獲取size的時候有可能進行offer蛙吏,poll或者remove操作源哩,導致獲取的元素個數(shù)不精確,所以在并發(fā)情況下size函數(shù)不是很有用鸦做。
LinkedTransferQueue
jdk7才提供這個類励烦,這個類實現(xiàn)了TransferQueue接口,也是基于鏈表的泼诱,對于所有給定的生產(chǎn)者都是先入先出的坛掠。與其他阻塞隊列的區(qū)別是:其他阻塞隊列,生產(chǎn)者生產(chǎn)數(shù)據(jù),如果隊列沒有滿屉栓,放下數(shù)據(jù)就走舷蒲,消費者獲取數(shù)據(jù),看到有數(shù)據(jù)獲取數(shù)據(jù)就走友多。而LinkedTransferQueue生產(chǎn)者放數(shù)據(jù)的時候牲平,如果此時消費者沒有獲取,則需阻塞等待直到有消費者過來獲取數(shù)據(jù)域滥。有點類似SynchronousQueue纵柿,但是LinkedTransferQueue是被設(shè)計有容量的。LinkedTransferQueue 通過使用CAS來實現(xiàn)并發(fā)控制骗绕,是一個無界的安全隊列藐窄。其長度可以無限延伸,當然帶來的問題也是顯而易見的酬土。
文章來源于網(wǎng)絡。
感謝大家閱讀格带,歡迎大家私信討論撤缴。給大家推薦一個Java技術(shù)交流群:473984645里面會分享一些資深架構(gòu)師錄制的視頻資料:有Spring,MyBatis叽唱,Netty源碼分析屈呕,高并發(fā)、高性能棺亭、分布式虎眨、微服務架構(gòu)的原理,JVM性能優(yōu)化镶摘、分布式架構(gòu)等這些成為架構(gòu)師必備的知識體系嗽桩。還能領(lǐng)取免費的學習資源,目前受益良多凄敢!
推薦大家閱讀:
Java高級架構(gòu)學習資料分享+架構(gòu)師成長之路?
個人整理了更多資料以PDF文件的形式分享給大家碌冶,需要查閱的程序員朋友可以來免費領(lǐng)取。還有我的學習筆記PDF文件也免費分享給有需要朋友涝缝!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扑庞,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子拒逮,更是在濱河造成了極大的恐慌罐氨,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,214評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件滩援,死亡現(xiàn)場離奇詭異栅隐,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評論 2 382
  • 文/潘曉璐 我一進店門约啊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來邑遏,“玉大人,你說我怎么就攤上這事恰矩〖呛校” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評論 0 341
  • 文/不壞的土叔 我叫張陵外傅,是天一觀的道長纪吮。 經(jīng)常有香客問我,道長萎胰,這世上最難降的妖魔是什么碾盟? 我笑而不...
    開封第一講書人閱讀 55,221評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮技竟,結(jié)果婚禮上冰肴,老公的妹妹穿的比我還像新娘。我一直安慰自己榔组,他們只是感情好熙尉,可當我...
    茶點故事閱讀 64,224評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著搓扯,像睡著了一般检痰。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锨推,一...
    開封第一講書人閱讀 49,007評論 1 284
  • 那天铅歼,我揣著相機與錄音,去河邊找鬼换可。 笑死椎椰,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的锦担。 我是一名探鬼主播俭识,決...
    沈念sama閱讀 38,313評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼洞渔!你這毒婦竟也來了套媚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 36,956評論 0 259
  • 序言:老撾萬榮一對情侶失蹤磁椒,失蹤者是張志新(化名)和其女友劉穎堤瘤,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體浆熔,經(jīng)...
    沈念sama閱讀 43,441評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡本辐,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,925評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慎皱。...
    茶點故事閱讀 38,018評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡老虫,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出茫多,到底是詐尸還是另有隱情祈匙,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評論 4 322
  • 正文 年R本政府宣布天揖,位于F島的核電站夺欲,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏今膊。R本人自食惡果不足惜些阅,卻給世界環(huán)境...
    茶點故事閱讀 39,234評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望斑唬。 院中可真熱鬧市埋,春花似錦、人聲如沸恕刘。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽雪营。三九已至,卻和暖如春衡便,著一層夾襖步出監(jiān)牢的瞬間献起,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評論 1 261
  • 我被黑心中介騙來泰國打工镣陕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留谴餐,地道東北人。 一個月前我還...
    沈念sama閱讀 45,467評論 2 352
  • 正文 我出身青樓呆抑,卻偏偏與公主長得像岂嗓,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子鹊碍,可洞房花燭夜當晚...
    茶點故事閱讀 42,762評論 2 345

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