Java并發(fā)編程:阻塞隊列
BlockingQueue
阻塞隊列分類
ArrayBlockingQueue :一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列。
LinkedBlockingQueue :一個由鏈表結(jié)構(gòu)組成的有界阻塞隊列鸠澈。
PriorityBlockingQueue :一個支持優(yōu)先級排序的無界阻塞隊列。
DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列休玩。
SynchronousQueue:一個不存儲元素的阻塞隊列狂鞋。
LinkedTransferQueue:一個由鏈表結(jié)構(gòu)組成的無界阻塞隊列片择。
LinkedBlockingDeque:一個由鏈表結(jié)構(gòu)組成的雙向阻塞隊列。
以上7類阻塞隊列中有LinkedBlockingQueue,DelayQueue,SynchronousQueue被用在了線程池當(dāng)中骚揍,其中LinkedBlockingQueue被使用在FixedThreadPool,SingleThreadExecutor中字管,SynchronousQueue被用在CachedThreadPool中,DelayQueue被使用在ScheduledThreadPoolExecutor中信不。
SynchronousQueue之所以用在CachedThreadPool中嘲叔,是因為SynchronousQueue不像ArrayBlockingQueue或LinkedListBlockingQueue,SynchronousQueue內(nèi)部并沒有數(shù)據(jù)緩存空間抽活,你不能調(diào)用peek()方法來看隊列中是否有數(shù)據(jù)元素硫戈,因為數(shù)據(jù)元素只有當(dāng)你試著取走的時候才可能存在,不取走而只想偷窺一下是不行的下硕,當(dāng)然遍歷這個隊列的操作也是不允許的丁逝。
SynchronousQueue的一個使用場景是在線程池里。Executors.newCachedThreadPool()就使用了SynchronousQueue梭姓,這個線程池根據(jù)需要(新任務(wù)到來時)創(chuàng)建新的線程霜幼,如果有空閑線程則會重復(fù)使用,線程空閑了60秒后會被回收誉尖,并不會等待空閑線程產(chǎn)生罪既。
1.非阻塞隊列中的幾個主要方法:
add(E e):將元素e插入到隊列末尾,如果插入成功铡恕,則返回true琢感;如果插入失敗(即隊列已滿)探熔,則會拋出異常驹针;
remove():移除隊首元素,若移除成功诀艰,則返回true牌捷;如果移除失敗(隊列為空)涡驮,則會拋出異常;
offer(E e):將元素e插入到隊列末尾喜滨,如果插入成功捉捅,則返回true;如果插入失斔浞纭(即隊列已滿)棒口,則返回false寄月;
poll():移除并獲取隊首元素,若成功无牵,則返回隊首元素漾肮;否則返回null;
peek():獲取隊首元素茎毁,若成功克懊,則返回隊首元素;否則返回null
對于非阻塞隊列七蜘,一般情況下建議使用offer谭溉、poll和peek三個方法,不建議使用add和remove方法橡卤。因為使用offer扮念、poll和peek三個方法可以通過返回值判斷操作成功與否,而使用add和remove方法卻不能達(dá)到這樣的效果碧库。注意柜与,非阻塞隊列中的方法都沒有進行同步措施。
2.阻塞隊列中的幾個主要方法:
阻塞隊列包括了非阻塞隊列中的大部分方法嵌灰,上面列舉的5個方法在阻塞隊列中都存在弄匕,但是要注意這5個方法在阻塞隊列中都進行了同步措施。除此之外伞鲫,阻塞隊列提供了另外4個非常有用的方法:
put(E e)
take()
offer(E e,long timeout, TimeUnit unit)
poll(long timeout, TimeUnit unit)
put方法用來向隊尾存入元素粘茄,如果隊列滿,則等待;
take方法用來從隊首取元素秕脓,如果隊列為空柒瓣,則等待;
offer方法用來向隊尾存入元素吠架,如果隊列滿芙贫,則等待一定的時間,當(dāng)時間期限達(dá)到時傍药,如果還沒有插入成功磺平,則返回false;否則返回true拐辽;
poll方法用來從隊首取元素拣挪,如果隊列空,則等待一定的時間俱诸,當(dāng)時間期限達(dá)到時菠劝,如果取到,則返回null睁搭;否則返回取得的元素赶诊;
阻塞隊列的實現(xiàn)原理
事實它和我們用Object.wait()笼平、Object.notify()和非阻塞隊列實現(xiàn)生產(chǎn)者-消費者的思路類似,只不過它把這些工作一起集成到了阻塞隊列中實現(xiàn)舔痪。
在并發(fā)編程中寓调,一般推薦使用阻塞隊列,這樣實現(xiàn)可以盡量地避免程序出現(xiàn)意外的錯誤锄码。
阻塞隊列使用最經(jīng)典的場景就是socket客戶端數(shù)據(jù)的讀取和解析夺英,讀取數(shù)據(jù)的線程不斷將數(shù)據(jù)放入隊列,然后解析線程不斷從隊列取數(shù)據(jù)解析巍耗。還有其他類似的場景秋麸,只要符合生產(chǎn)者-消費者模型的都可以使用阻塞隊列。 具體見轉(zhuǎn)載