阻塞佇列與非阻塞佇列區別應用場景
轉載自:http://blog.csdn.net/u012881904/article/details/51491736
作者:小汪
阻塞佇列與普通佇列的區別在於,當佇列是空的時,從佇列中獲取元素的操作將會被阻塞,或者當佇列是滿時,往佇列裡新增元素的操作會被阻塞。試圖從空的阻塞佇列中獲取元素的執行緒將會被阻塞,直到其他的執行緒往空的佇列插入新的元素。同樣,試圖往已滿的阻塞佇列中新增新元素的執行緒同樣也會被阻塞,直到其他的執行緒使佇列重新變得空閒起來,如從佇列中移除一個或者多個元素,或者完全清空佇列.
1.ArrayDeque, (陣列雙端佇列)
2.PriorityQueue, (優先順序佇列)
3.ConcurrentLinkedQueue, (基於連結串列的併發佇列)
4.DelayQueue, (延期阻塞佇列)(阻塞佇列實現了BlockingQueue介面)
5.ArrayBlockingQueue, (基於陣列的併發阻塞佇列)
6.LinkedBlockingQueue, (基於連結串列的FIFO阻塞佇列)
7.LinkedBlockingDeque, (基於連結串列的FIFO雙端阻塞佇列)
8.PriorityBlockingQueue, (帶優先順序的無界阻塞佇列)
9.SynchronousQueue (併發同步阻塞佇列)
阻塞佇列和生產者-消費者模式
阻塞佇列(Blocking queue)提供了可阻塞的put和take方法,它們與可定時的offer和poll是等價的。如果Queue已經滿了,put方法會被阻塞直到有空間可用;如果Queue是空的,那麼take方法會被阻塞,直到有元素可用。Queue的長度可以有限,也可以無限;無限的Queue永遠不會充滿,所以它的put方法永遠不會阻塞。
阻塞佇列支援生產者-消費者設計模式。一個生產者-消費者設計分離了“生產產品”和“消費產品”。該模式不會發現一個工作便立即處理,而是把工作置於一個任務(“to do”)清單中,以備後期處理。生產者-消費者模式簡化了開發,因為它解除了生產者和消費者之間相互依賴的程式碼。生產者和消費者以不同的或者變化的速度生產和消費資料,生產者-消費者模式將這些活動解耦,因而簡化了工作負荷的管理。
生產者-消費者設計是圍繞阻塞佇列展開的,生產者把資料放入佇列,並使資料可用,當消費者為適當的行為做準備時會從佇列中獲取資料。生產者不需要知道消費者的省份或者數量,甚至根本沒有消費者—它們只負責把資料放入佇列。類似地,消費者也不需要知道生產者是誰,以及是誰給它們安排的工作。BlockingQueue可以使用任意數量的生產者和消費者,從而簡化了生產者-消費者設計的實現。最常見的生產者-消費者設計是將執行緒池與工作佇列相結合。
阻塞佇列簡化了消費者的編碼,因為take會保持阻塞直到可用資料出現。如果生產者不能足夠快地產生工作,讓消費者忙碌起來,那麼消費者只能一直等待,直到有工作可做。同時,put方法的阻塞特性也大大地簡化了生產者的編碼;如果使用一個有界佇列,那麼當佇列充滿的時候,生產者就會阻塞,暫不能生成更多的工作,從而給消費者時間來趕進進度。
有界佇列是強大的資源管理工具,用來建立可靠的應用程式:它們遏制那些可以產生過多工作量、具有威脅的活動,從而讓你的程式在面對超負荷工作時更加健壯。
雖然生產者-消費者模式可以把生產者和消費者的程式碼相互解耦合,但是它們的行為還是間接地通過共享佇列耦合在一起了
類庫中包含一些BlockingQueue的實現,其中LinkedBlockingQueue和ArrayBlockingQueue是FIFO佇列,與 LinkedList和ArrayList相似,但是卻擁有比同步List更好的併發效能。PriorityBlockingQueue是一個按優先順序順序排序的佇列,當你不希望按照FIFO的屬性處理元素時,這個PriorityBolckingQueue是非常有用的。正如其他排序的容器一樣,PriorityBlockingQueue可以比較元素本身的自然順序(如果它們實現了Comparable),也可以使用一個 Comparator進行排序。
最後一個BlockingQueue的實現是SynchronousQueue,它根本上不是一個真正的佇列,因為它不會為佇列元素維護任何儲存空間。不過,它維護一個排隊的執行緒清單,這些執行緒等待把元素加入(enqueue)佇列或者移出(dequeue)佇列。因為SynchronousQueue沒有儲存能力,所以除非另一個執行緒已經準備好參與移交工作,否則put和take會一直阻止。SynchronousQueue這類佇列只有在消費者充足的時候比較合適,它們總能為下一個任務作好準備。
非阻塞演算法
基於鎖的演算法會帶來一些活躍度失敗的風險。如果執行緒在持有鎖的時候因為阻塞I/O,頁面錯誤,或其他原因發生延遲,很可能所有的執行緒都不能前進了。
一個執行緒的失敗或掛起不應該影響其他執行緒的失敗或掛起,這樣的演算法成為非阻塞(nonblocking)演算法;如果演算法的每一個步驟中都有一些執行緒能夠繼續執行,那麼這樣的演算法稱為鎖自由(lock-free)演算法。線上程間使用CAS進行協調,這樣的演算法如果能構建正確的話,它既是非阻塞的,又是鎖自由的。非競爭的CAS總是能夠成功,如果多個執行緒以一個CAS競爭,總會有一個勝出並前進。非阻塞演算法堆死鎖和優先順序倒置有“免疫性”(但它們可能會出現飢餓和活鎖,因為它們允許重進入)。
非阻塞演算法通過使用低層次的併發原語,比如比較交換,取代了鎖。原子變數類向用戶提供了這些底層級原語,也能夠當做“更佳的volatile變數”使用,同時提供了整數類和物件引用的原子化更新操作。