阻塞队列-BlockningQueue
阻塞隊列的前言介紹引用于https://www.cnblogs.com/aspirant/p/8657801.html,寫的挺好有興趣可以看一看
一. 前言
在新增的Concurrent包中,BlockingQueue很好的解決了多線程中,如何高效安全“傳輸”數據的問題。通過這些高效并且線程安全的隊列類,為我們快速搭建高質量的多線程程序帶來極大的便利。本文詳細介紹了BlockingQueue家庭中的所有成員,包括他們各自的功能以及常見使用場景。
二. 認識BlockingQueue
阻塞隊列,顧名思義,首先它是一個隊列,而一個隊列在數據結構中所起的作用大致如下圖所示:
從上圖我們可以很清楚看到,通過一個共享的隊列,可以使得數據由隊列的一端輸入,從另外一端輸出;
常用的隊列主要有以下兩種:(當然通過不同的實現方式,還可以延伸出很多不同類型的隊列,DelayQueue就是其中的一種)
先進先出(FIFO):先插入的隊列的元素也最先出隊列,類似于排隊的功能。從某種程度上來說這種隊列也體現了一種公平性。
后進先出(LIFO):后插入隊列的元素最先出隊列,這種隊列優先處理最近發生的事件。
多線程環境中,通過隊列可以很容易實現數據共享,比如經典的“生產者”和“消費者”模型中,通過隊列可以很便利地實現兩者之間的數據共享。假設我們有若干生產者線程,另外又有若干個消費者線程。如果生產者線程需要把準備好的數據共享給消費者線程,利用隊列的方式來傳遞數據,就可以很方便地解決他們之間的數據共享問題。但如果生產者和消費者在某個時間段內,萬一發生數據處理速度不匹配的情況呢?理想情況下,如果生產者產出數據的速度大于消費者消費的速度,并且當生產出來的數據累積到一定程度的時候,那么生產者必須暫停等待一下(阻塞生產者線程),以便等待消費者線程把累積的數據處理完畢,反之亦然。然而,在concurrent包發布以前,在多線程環境下,我們每個程序員都必須去自己控制這些細節,尤其還要兼顧效率和線程安全,而這會給我們的程序帶來不小的復雜度。好在此時,強大的concurrent包橫空出世了,而他也給我們帶來了強大的BlockingQueue。(在多線程領域:所謂阻塞,在某些情況下會掛起線程(即阻塞),一旦條件滿足,被掛起的線程又會自動被喚醒),下面兩幅圖演示了BlockingQueue的兩個常見阻塞場景:
如上圖所示:當隊列中沒有數據的情況下,消費者端的所有線程都會被自動阻塞(掛起),直到有數據放入隊列。
如上圖所示:當隊列中填滿數據的情況下,生產者端的所有線程都會被自動阻塞(掛起),直到隊列中有空的位置,線程被自動喚醒。
這也是我們在多線程環境下,為什么需要BlockingQueue的原因。作為BlockingQueue的使用者,我們再也不需要關心什么時候需要阻塞線程,什么時候需要喚醒線程,因為這一切BlockingQueue都給你一手包辦了。
1.ArrayBlockingQueue
(1).拋出異常
public static void main(String[] args) {BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);System.out.println(blockingQueue.add("a"));System.out.println(blockingQueue.add("b"));System.out.println(blockingQueue.add("c"));System.out.println(blockingQueue.add("c"));System.out.println(blockingQueue.element());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());System.out.println(blockingQueue.remove());}結果
(2)特殊值
public static void main(String[] args) {BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);System.out.println(blockingQueue.offer("a"));System.out.println(blockingQueue.offer("b"));System.out.println(blockingQueue.offer("b"));System.out.println(blockingQueue.offer("b"));System.out.println(blockingQueue.peek());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());System.out.println(blockingQueue.poll());}(3)阻塞
public static void main(String[] args) throws InterruptedException {BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<>(3);blockingQueue.put("a");blockingQueue.put("b");blockingQueue.put("c");System.out.println("===========");System.out.println(blockingQueue.take());System.out.println(blockingQueue.take());System.out.println(blockingQueue.take());System.out.println(blockingQueue.take());}(4)超時
System.out.println(blockingQueue.offer("a", 3L, TimeUnit.SECONDS));System.out.println(blockingQueue.offer("b", 3L, TimeUnit.SECONDS));System.out.println(blockingQueue.offer("c", 3L, TimeUnit.SECONDS));System.out.println(blockingQueue.offer("d", 3L, TimeUnit.SECONDS));System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS));System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS));System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS));System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS));2.SynchronizedQueue同步隊列
SynchronousQueue:不存儲元素的阻塞隊列,也即單個元素的隊列。
SynchronousQueue沒有容量。
與其他BlockingQueue不同,SynchronousQueue是一個不存儲元素的BlockingQueue。
每一個put操作必須要等待一個take操作,否則不能繼續添加元素,反之亦然。
例子:阻塞隊列來寫生產者消費者
總結
以上是生活随笔為你收集整理的阻塞队列-BlockningQueue的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 100W高速快充成标配!realme G
- 下一篇: 数据结构 - 多路搜索树(2-3树、b树