跳到主要內容

阻塞隊列一——java中的阻塞隊列

目錄



  • 阻塞隊列簡介:介紹阻塞隊列的特性與應用場景

  • java中的阻塞隊列:介紹java中實現的供開發者使用的阻塞隊列

  • BlockQueue中方法:介紹阻塞隊列的API接口

  • 阻塞隊列的實現原理:具體的例子說明阻塞隊列的實現原理

  • 總結


阻塞隊列簡介


阻塞隊列(BlockingQueue)首先是一個支持先進先出的隊列,與普通的隊列完全相同;
其次是一個支持阻塞操作的隊列,即:



  • 當隊列滿時,會阻塞執行插入操作的線程,直到隊列不滿。

  • 當隊列為空時,會阻塞執行獲取操作的線程,直到隊列不為空。


阻塞隊列用在多線程的場景下,因此阻塞隊列使用了鎖機制來保證同步,這裏使用的可重入鎖;
而對於阻塞與喚醒機制則有與鎖綁定的Condition實現


應用場景:生產者消費者模式


java中的阻塞隊列


java中的阻塞隊列根據容量可以分為有界隊列和無界隊列:



  • 有界隊列:隊列中只能存儲有限個元素,超出后存放元素線程會被阻塞或者失敗。

  • 無界隊列:隊列中可以存儲無限個元素。


java8中提供了7種阻塞隊列阻塞隊列供開發者使用,如下錶:







































類名 描述
ArrayBlockingQueue 一個由數組結構組成的有界阻塞隊列
LinkedBlockingQueue 由鏈表結構組成的有界阻塞隊列(默認大小Integer.MAX_VALUE)
PriorityBlockingQueue 支持優先級排序的無界阻塞隊列
DelayQueue 使用優先級隊列實現的延遲無界阻塞隊列
SynchronousQueue 不存儲元素的阻塞隊列,即單個元素的隊列
LinkedTransferQueue 由鏈表結構組成的無界阻塞隊列
LinkedBlockingDeque 由鏈表結構組成的雙向阻塞隊列

另外還有一個在ScheduledThreadPoolExecutor中實現的DelayedWorkQueue阻塞隊列,
但這個阻塞隊列開發者不能使用。它們之間的UML類圖如下圖:


BlockingQueue接口是阻塞隊列對外的訪問接口,所有的阻塞隊列都實現了BlockQueue中的方法


BlockQueue中方法


作為一個隊列的核心方法就是入隊和出隊。由於存在阻塞策略,BlockQueue將出隊入隊的情況分為了四組,每組提供不同的方法:



  • 拋出異常:當隊列滿時,如果再往隊列中插入元素,則拋出IllegalStateException異常;
    當隊列為空時,從隊列中獲取元素則拋出NoSuchElementException異常。


  • 返回特定值(布爾值):當隊列滿時,如果再往隊列中插入元素,則返回false;當隊列為空時,從隊列中獲取元素則返回null。


  • 一直阻塞:當隊列滿時,如果再往隊列中插入元素,阻塞當前線程直到隊列中至少一個被移除或者響應中斷退出;
    當隊列為空時,則阻塞當前線程直到至少一個元素元素入隊或者響應中斷退出。


  • 超時退出:當隊列滿時,如果再往隊列中插入元素,阻塞當前線程直到隊列中至少一個被移除或者達到指定的等待時間退出或者響應中斷退出;
    當隊列為空時,則阻塞當前線程直到至少一個元素元素入隊或者達到指定的等待時間退出或者響應中斷退出。



對於每種情況BlockingQueue提供的方法如下錶:



































方法\處理方式 拋出異常 返回特定值(布爾值) 一直阻塞 超時退出
插入 add(e) offer(e) put(e) offer(e,time,unit)
移除 remove() poll() take() poll(time.unit)
檢查 element() peek() 不可用 不可用

上述方法一般用於生產者-消費者模型中,是其中的生產和消費操作隊列的核心方法。
除了這些方法,BlockingQueue還提供了一些其他的方法如下錶:















































方法名稱 描述
remove(Object o) 從隊列中移除一個指定值
size() 獲取隊列中元素的個數
contains(Object o) 判斷隊列是否包含指定的元素,但是這個元素在這次判斷完可能就會被消費
drainTo(Collection<? super E> c) 將隊列中元素放在給定的集合中,並返回添加的元素個數
drainTo(Collection<? super E> c, int maxElements) 將隊列中元素取maxElements(不超過隊列中元素個數)個放在給定的集合中,並返回添加的元素個數
remainingCapacity() 計算隊列中還可以存放的元素個數
toArray() 以objetc數組的形式獲取隊列中所有的元素
toArray(T[] a) 以給定類型數組的方式獲取隊列中所有的元素
clear() 清空隊列,危險的操作

阻塞隊列的實現原理


阻塞隊列的實現依靠通知模式實現:當生產者向滿了的隊列中添加元素時,會阻塞住生產者,
直到消費者消費了一個隊列中的元素後會通知消費者隊列可用,此時再由生產者向隊列中添加元素。反之亦然。


阻塞隊列的阻塞喚醒依靠Condition——條件隊列來實現。


ArrayBlockingQueue為例說明:


ArrayBlockingQueue的定義:


public class ArrayBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {

/** The queued items */
//以數組的結構存儲隊列的元素,採用的是循環數組
final Object[] items;

/** items index for next take, poll, peek or remove */
//隊列的隊頭索引
int takeIndex;

/** items index for next put, offer, or add */
//隊列的隊尾索引
int putIndex;

/** Number of elements in the queue */
//隊列中元素的個數
int count;

/** Main lock guarding all access */
//對於ArrayBlockingQueue所有的操作都需要加鎖,
final ReentrantLock lock;

/** Condition for waiting takes */
//條件隊列,當隊列為空時阻塞消費者並在生產者生產後喚醒消費者
private final Condition notEmpty;

/** Condition for waiting puts */
//條件隊列,當隊列滿時阻塞生產者,並在消費者消費隊列后喚醒生產者
private final Condition notFull;
}

根據類的定義字段可以看到,有兩個Condition條件隊列,猜測以下過程



  • 當隊列為空,消費者試圖消費時應該調用notEmpty.await()方法阻塞,並在生產者生產後調用notEmpty.single()方法

  • 當隊列已滿,生產者試圖放入元素應調用notFull.await()方法阻塞,並在消費者消費隊列后調用notFull.single()方法


向隊列中添加元素put()方法的添加過程。


    /**
* 向隊列中添加元素
* 當隊列已滿時需要阻塞當前線程
* 放入元素后喚醒因隊列為空阻塞的消費者
*/
public void put(E e) throws InterruptedException {
checkNotNull(e);
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//當隊列已滿時需要notFull.await()阻塞當前線程
//offer(e,time,unit)方法就是阻塞的時候加了超時設定
while (count == items.length)
notFull.await();
//放入元素的過程
enqueue(e);
} finally {
lock.unlock();
}
}

/**enqueue實際添加元素的方法*/
private void enqueue(E x) {
// assert lock.getHoldCount() == 1;
// assert items[putIndex] == null;
final Object[] items = this.items;
items[putIndex] = x;
if (++putIndex == items.length)
putIndex = 0;
count++;
//如果條件隊列中存在等待的線程
//喚醒
notEmpty.signal();
}

從隊列中獲取元素take()方法的獲取過程。


    /**
* 從隊列中獲取元素
* 當隊列已空時阻塞當前線程
* 從隊列中消費元素后喚醒等待的生產線程
*/
public E take() throws InterruptedException {
final ReentrantLock lock = this.lock;
lock.lockInterruptibly();
try {
//隊列為空需要阻塞當前線程
while (count == 0)
notEmpty.await();
//獲取元素的過程
return dequeue();
} finally {
lock.unlock();
}
}

/**dequeue實際消費元素的方法*/
private E dequeue() {
// assert lock.getHoldCount() == 1;
// assert items[takeIndex] != null;
final Object[] items = this.items;
@SuppressWarnings("unchecked")
E x = (E) items[takeIndex];
items[takeIndex] = null;
if (++takeIndex == items.length)
takeIndex = 0;
count--;
if (itrs != null)
itrs.elementDequeued();
//消費元素后從喚醒阻塞的生產者線程
notFull.signal();
return x;
}

總結


阻塞隊列提供了不同於普通隊列的增加、刪除元素的方法,核心在與隊列滿時阻塞生產者和隊列空時阻塞消費者。
這一阻塞過程依靠與鎖綁定的Condition對象實現。Condition接口的實現在AQS中實現,具體的實現類是
ConditionObject

本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理

【其他文章推薦】



※別再煩惱如何寫文案,掌握八大原則!



網頁設計一頭霧水該從何著手呢? 台北網頁設計公司幫您輕鬆架站!



※超省錢租車方案



※教你寫出一流的銷售文案?



網頁設計最專業,超強功能平台可客製化



※產品缺大量曝光嗎?你需要的是一流包裝設計!



Orignal From: 阻塞隊列一——java中的阻塞隊列

留言

這個網誌中的熱門文章

掃地機器人可以隨身帶上飛機嗎?我想要拿去送給國外的朋友

掃地機器人如果要隨身戴上飛機需要滿足兩個條件: 一個是掃地機器人連同你的隨身行李,整體的體積和重量要符合上機條件,這個具體每家航空公司都不同,可以諮詢,簡單的說就是隨身行李不要超寬超重。 還有一個就是由於掃地機器人內置了鋰電池,所以內置電池的容量要符合相關規定,每個掃地機器人電池容量都不同,具體自行查詢。 根據民航的相關安全要求,凡帶有鋰電池的電子設備均不可以托運,但符合重量要求,尺寸要求以及電量要求的鋰電池及其設備是可以帶上飛機的。 《鋰電池航空運輸規範》中內含鋰離子電池的設備電池額定能量不應超過100Wh的規定,符合國標GB31241-2014,並通過UN38.3航空運輸認證等國際安全標準,所以可以帶上飛機。但是不能托運,只能隨身攜帶。 掃地機器人     掃地機器人     掃地機器人吸塵器 http://www.greenh3y.com/?p=400 Orignal From: 掃地機器人可以隨身帶上飛機嗎?我想要拿去送給國外的朋友

不滿國際規範斷財路 非洲多國擬退野生動保公約

摘錄自2019年09月01日中央通訊社非洲報導 非洲南部多國揚言退出「瀕臨絕種野生動植物國際貿易公約」,因為公約多數成員拒絕放寬象牙與犀牛角交易,並且幾乎全面禁止將野生捕獲的大象送到動物園。 這個公約嚴格規範全球野生動物交易,包括限制象牙與犀牛角交易。 本週在日內瓦召開修訂「瀕臨絕種野生動植物國際貿易公約」(CITES)的會議期間,由於區域集團非南開發共同體(SADC)的多項提案遭否決,這個集團與公約的關係惡化。 全球大象數量最多的區域波札那、納米比亞與辛巴威要求販售取自自然死亡、充公與汰除的大象象牙,這項提議被居多數的101票否決。 40多年前制訂的CITES規範約3萬6000種動植物交易,並設計有助於遏止非法交易和制裁違規國家的機制。 不過有16個成員國的非南開發共同體部分會員批評CITES對非洲國家的問題視若無睹。 坦尚尼亞環境部長西蒙巴徹恩(George Simbachawene)於日內瓦召開的會議中表示:「結果無法採取進步、公平、包容與基於科學的的保育策略。」 他說:「該是認真重新考慮我們加入CITES是否有任何實質益處的時候了。」 本站聲明:網站內容來源環境資訊中心https://e-info.org.tw/,如有侵權,請聯繫我們,我們將及時處理 【搬家相關資訊指南】 台中搬家 , 彰化搬家 , 南投搬家 前需注意的眉眉角角,別等搬了再說! 避免吃悶虧無故遭抬價! 台中搬家公司 免費估價,有契約讓您安心有保障! 評比 彰化搬家公司費用 , 南投搬家公司費用 收費行情懶人包大公開 彰化搬家費用 , 南投搬家費用 ,距離,噸數怎麼算?達人教你簡易估價知識! Orignal From: 不滿國際規範斷財路 非洲多國擬退野生動保公約

春河劇團《叫我林彩香》 9/16新竹縣政府文化局登場

春河劇團《叫我林彩香》舞台劇訂於9月16日下午在新竹縣政府文化局演藝廳演出。(圖/新竹縣政府提供) 記者蔡孟尚/新竹報導 春河劇團《叫我林彩香》舞台劇訂於9月16日下午在新竹縣政府文化局演藝廳登場,導演也是劇團團長郎祖筠表示,《叫我林彩香!》是公視劇《我的婆婆怎麼那麼可愛》的前傳,劇情回到婆婆年輕時那個經濟起飛的年代,透過母女之間的相處,刻畫台灣女性在社會轉變過程中的角色與地位,「林彩香」是個代名詞,每個自我意識覺醒的女生,都是可敬、可愛的林彩香。 《叫我林彩香》 演員有高玉珊、呂曼茵、鍾瑶、陳漢典、楊小黎、吳怡霈,劇情以以女性視角剖析傳統台灣家庭、社會,除了可以看到當時代人們對於女性角色的刻板印象外,也可以一窺台灣當時的時代樣貌,例如大家族裡的婆婆是如何咄咄逼人、母親一個女人如何隻身照養一大票小孩,而作為一個女人到底又該如何面對整個社會?年輕時期的彩香嚮往外面世界的自由,從女兒成為了母親,又從母親變成了婆婆,彩香的重心似乎又從外界,慢慢的被拉回家庭中,《叫我林彩香!》劇名的由來,是林彩香對著整個世界的一聲吶喊,不管現在是什麼身分,她最希望的便是可以讓自己被所有給認可。 請問 台中電動車 哪裡在賣比較便宜可以到台中景泰電動車門市去看看總店:臺中市潭子區潭秀里雅潭路一段102-1號。 電動車補助 推薦評價好的 iphone維修 中心擁有專業的維修技術團隊,同時聘請資深iphone手機維修專家,現場說明手機問題,快速修理,沒修好不收錢住家的頂樓裝 太陽光電 聽說可發揮隔熱功效一線推薦東陽能源擁有核心技術、產品研發、系統規劃設置、專業團隊的太陽能發電廠商。 網頁設計 一頭霧水該從何著手呢? 回頭車 貨運收費標準宇安交通關係企業,自成立迄今,即秉持著「以誠待人」、「以實處事」的企業信念 台中搬家公司 教你幾個打包小技巧,輕鬆整理裝箱!還在煩惱搬家費用要多少哪?台中大展搬家線上試算搬家費用,從此不再擔心「物品怎麼計費」、「多少車才能裝完」 台中搬家 公司費用怎麼算?擁有20年純熟搬遷經驗,提供免費估價且流程透明更是5星評價的搬家公司好山好水 露營車 漫遊體驗露營車x公路旅行的十一個出遊特色。走到哪、玩到哪,彈性的出遊方案,行程跟出發地也可客製 Google地圖已可更新顯示 潭子電動車 充電站設置地點!!廣告預算用在刀口上, 台北網頁設計 公司幫您達到更多曝光...