JUC學習 阻塞佇列

2021-10-10 11:18:40 字數 3604 閱讀 8153

在這篇部落格中我們接觸的佇列都是非阻塞佇列,比如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 不可用不可用 丟擲異常 當阻塞佇列滿時...