在java.util.concurrent包中的BlockingQueue接口,其存取操作,是線程安全的.在這篇文章中,我會告訴你,如何來使用這個接口.
這篇文章中,不會告訴你如何實(shí)現(xiàn)一個BlockingQueue.如果你對此感興趣,那請參考文末的資料.
BlockingQueue的用法
BlockingQueue的典型使用場景是有一個生產(chǎn)者生產(chǎn)產(chǎn)品,然后有一個消費(fèi)者消費(fèi)產(chǎn)品.如下圖所示:
生產(chǎn)者線程會生產(chǎn)一個產(chǎn)品,然后把它放入隊列中,直到這個隊列達(dá)到了上限.一旦隊列達(dá)到上限,生產(chǎn)者線程會被阻塞,直到有一個消費(fèi)者線程消費(fèi)了隊列中的一個產(chǎn)品.
同樣,消費(fèi)者線程會從隊列中取出一個產(chǎn)品,然后消費(fèi)它,直到這個隊列中沒有產(chǎn)品了.如果隊列中沒有產(chǎn)品,那么消費(fèi)者線程會被阻塞,直到隊列中有產(chǎn)品.
BlockingQueue中的方法
針對隊列中產(chǎn)品的操作,BlockingQueue提供了四類方法:
我們來解釋一下第一行中的那些字段的含義:
- Throws Exception:
如果操作不能立即執(zhí)行,比如消費(fèi)者線程嘗試消費(fèi)空隊列中的產(chǎn)品,則會拋出異常. - Special Value:
如果操作不能立即執(zhí)行,則返回一個特殊值.一般是true或者false. - Blocks:
如果操作不能立即執(zhí)行,則阻塞此方法. - Times Out:
如果操作不能理解成功,則阻塞線程并等待給定的時間.返回一個Special Value來表明調(diào)用是否成功.
隊列中,不可以插入一個null.如果你這么做,那么BlockingQueue會給你拋出一個NullPointerException.
我們可以訪問BlockingQueue中的任意產(chǎn)品,而不用非得是開頭或者結(jié)尾位置的產(chǎn)品.例如,如果你打算移除隊列中的一個產(chǎn)品,那你可以采用remove(0)的方法.然而,這個方法的效率并不是特別高,所以你應(yīng)該盡量避免使用它.
BlockingQueue的實(shí)現(xiàn)
BlockingQueue只是一個接口,我們實(shí)際上會使用的,還是它的實(shí)現(xiàn).java.util.concurrent包中,提供了這些BlockingQueue的實(shí)現(xiàn):
我們會在后面的文章中,介紹它們.
BlockingQueue的例子
下面是一個使用BlockingQueue的例子.其中我們用到了ArrayBlockingQueue這個實(shí)現(xiàn).
消費(fèi)者每次生產(chǎn)完一個產(chǎn)品,都會暫停一秒中,這將導(dǎo)致我們的消費(fèi)者也暫時被阻塞.