在這篇部落格中我們接觸的佇列都是非阻塞佇列,比如priorityqueue、linkedlist(linkedlist是雙向鍊錶,它實現了dequeue介面),阻塞佇列常用於執行緒池和生產者消費者的問題中
使用非阻塞佇列的時候有乙個很大問題就是:它不會對當前執行緒產生阻塞,那麼在面對類似消費者-生產者的模型時,就必須額外地實現同步策略以及執行緒間喚醒策略,這個實現起來就非常麻煩。
阻塞佇列,顧名思義,首先它是乙個佇列,而乙個佇列在資料結構中所起的作用大致如下圖所示:
從上圖我們可以很清楚看到,通過乙個共享的佇列,可以使得資料由佇列的一端輸入,從另外一端輸出;
常用的佇列主要有以下兩種:
先進先出(fifo):先插入的佇列的元素也最先出佇列,類似於排隊的功能。從某種程度上來說這種佇列也體現了一種公平性。
後進先出(lifo):後插入佇列的元素最先出佇列,這種佇列優先處理最近發生的事件。
阻塞佇列常用於生產者和消費者的場景,生產者執行緒可以把生產結果存到阻塞佇列中,而消費者執行緒把中間結果取出並在將來修改它們。
佇列會自動平衡負載,如果生產者執行緒集執行的比消費者執行緒集慢,則消費者執行緒集在等待結果時就會阻塞;如果生產者執行緒集執行的快,那麼它將等待消費者執行緒集趕上來。
作為blockingqueue的使用者,我們再也不需要關心什麼時候需要阻塞執行緒,什麼時候需要喚醒執行緒,因為這一切blockingqueue都給你一手包辦了。
看下blockingqueue的核心方法
1、放入資料
(1)put(e e):put方法用來向隊尾存入元素,如果佇列滿,則等待。
(2)offer(e o, long timeout, timeunit unit):offer方法用來向隊尾存入元素,如果佇列滿,則等待一定的時間,當時間期限達到時,如果還沒有插入成功,則返回false;否則返回true;
2、獲取資料
(1)take():take方法用來從隊首取元素,如果隊列為空,則等待;
(2)drainto():一次性從blockingqueue獲取所有可用的資料物件(還可以指定獲取資料的個數),通過該方法,可以提公升獲取資料效率;不需要多次分批加鎖或釋放鎖。
(3)poll(time):取走blockingqueue裡排在首位的物件,若不能立即取出,則可以等time引數規定的時間,取不到時返回null;
(4)poll(long timeout, timeunit unit):poll方法用來從隊首取元素,如果佇列空,則等待一定的時間,當時間期限達到時,如果取到,則返回null;否則返回取得的元素;
在了解了blockingqueue的基本功能後,讓我們來看看blockingqueue家庭大致有哪些成員?
jdk7 提供了 7 個阻塞佇列。分別是
arrayblockingqueue:乙個由陣列結構組成的有界阻塞佇列。
linkedblockingqueue:乙個由鍊錶結構組成的有界阻塞佇列。
priorityblockingqueue:乙個支援優先順序排序的無界阻塞佇列。
delayqueue:乙個使用優先順序佇列實現的無界阻塞佇列。
synchronousqueue:乙個不儲存元素的阻塞佇列。
linkedtransferqueue:乙個由鍊錶結構組成的無界阻塞佇列。
linkedblockingdeque:乙個由鍊錶結構組成的雙向阻塞佇列
1、arrayblockingqueue
基於陣列實現的乙個阻塞佇列,在建立arrayblockingqueue物件時必須制定容量大小。並且可以指定公平性與非公平性,預設情況下為非公平的,即不保證等待時間最長的佇列最優先能夠訪問佇列。
2、linkedblockingqueue
基於鍊錶實現的乙個阻塞佇列,在建立linkedblockingqueue物件時如果不指定容量大小,則預設大小為integer.max_value。
3、priorityblockingqueue
以上2種佇列都是先進先出佇列,而priorityblockingqueue卻不是,它會按照元素的優先順序對元素進行排序,按照優先順序順序出隊,每次出隊的元素都是優先順序最高的元素。注意,此阻塞隊列為無界阻塞佇列,即
容量沒有上限(通過原始碼就可以知道,它沒有容器滿的訊號標誌),前面2種都是有界佇列。
4、delayqueue
基於priorityqueue,一種延時阻塞佇列,delayqueue中的元素只有當其指定的延遲時間到了,才能夠從佇列中獲取到該元素。delayqueue也是乙個無界佇列,因此往佇列中插入資料的操作(生產者)永遠不會
被阻塞,而只有獲取資料的操作(消費者)才會被阻塞。
這裡通過linkedblockingqueue實現生產消費模式
(1)測試類
public
class
blockingqueuetest
}
(2)生產者
/**
* 生產者執行緒
*/public
class
producer
implements
runnable
public
void
run()}
}catch
(interruptedexception e)
finally
}public
void
stop()
}
(3)消費者
/**
* 消費者執行緒
*/public
class
consumer
implements
runnable
public
void
run(
)else}}
catch
(interruptedexception e)
finally
}}
執行結果(其中一種)
阻塞佇列目前我主要是進行乙個大概的了解,文章內容都源於網上的,在此用於記錄,方便以後查詢用;
每天進步一點點!!
JUC 阻塞佇列
什麼是阻塞佇列 阻塞佇列常用於生產者和消費者場景,生產者是向佇列裡新增元素的執行緒,消費者是從佇列裡獲取元素的執行緒。阻塞佇列就是生產者用來存放元素 消費者用來獲取元素的容器 為什麼要使用阻塞佇列 就是適用在不得不阻塞的場景如上面所說生產者 和 消費者場景中 要是佇列中為空 消費者不得不進行阻塞 佇...
JUC學習筆記 阻塞佇列
阻塞佇列是乙個佇列。當佇列是空的,從佇列中獲取元素的操作將會被阻塞 當佇列是滿的。從佇列中新增元素的操作將會阻塞。在多執行緒領域 所謂阻塞,在某些情況下會掛起執行緒 即阻塞 一旦條件滿足,被掛起的執行緒又會自動被喚起。好處是我們不需要關心什麼時候需要阻塞執行緒,什麼時候需要喚醒執行緒,因為這一切bl...
juc 阻塞佇列BlockingQueue
阻塞佇列blockingqueue的方法分類 方法型別 丟擲異常 特殊值阻塞 超時插入 add e offer e put e offer e,time,unit 移除remove poll take poll time,unit 檢查element peek 不可用不可用 丟擲異常 當阻塞佇列滿時...