精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

JUC之阻塞隊列BlockingQueue竟然有8種類型?

開發(fā) 前端
隊列是一種特殊的線性表,是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)。它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作。進(jìn)行插入操作的端稱為隊尾,進(jìn)行刪除操作的端稱為隊頭。隊列中沒有元素時,稱為空隊列。

 隊列是一種特殊的線性表,是一種先進(jìn)先出(FIFO)的數(shù)據(jù)結(jié)構(gòu)。它只允許在表的前端(front)進(jìn)行刪除操作,而在表的后端(rear)進(jìn)行插入操作。進(jìn)行插入操作的端稱為隊尾,進(jìn)行刪除操作的端稱為隊頭。隊列中沒有元素時,稱為空隊列。

下面是Queue類的繼承關(guān)系圖:


Queue


Queue:隊列的上層接口,提供了插入、刪除、獲取元素這3種類型的方法,而且對每一種類型都提供了兩種方式,先來看看插入方法:

  • add(E e):插入元素到隊尾,插入成功返回true,沒有可用空間拋出異常 IllegalStateException。
  • offer(E e): 插入元素到隊尾,插入成功返回true,否則返回false。

add和offer作為插入方法的唯一不同就在于隊列滿了之后的處理方式。add拋出異常,而offer返回false。

再來看看刪除和獲取元素方法(和插入方法類似):

  • remove():獲取并移除隊首的元素,該方法和poll方法的不同之處在于,如果隊列為空該方法會拋出異常,而poll不會。
  • poll():獲取并移除隊首的元素,如果隊列為空,返回null。
  • element():獲取隊列首的元素,該方法和peek方法的不同之處在于,如果隊列為空該方法會拋出異常,而peek不會。
  • peek():獲取隊列首的元素,如果隊列為空,返回null。

如果隊列是空,remove和element方法會拋出異常,而poll和peek返回null。

  • Queue 是單向隊列,為了提供更強(qiáng)大的功能,JDK在1.6的時候新增了一個雙向隊列
  • Deque,用來實現(xiàn)更靈活的隊列操作。

Deque

Deque在Queue的基礎(chǔ)上,增加了以下幾個方法:

  • addFirst(E e):在前端插入元素,異常處理和add一樣;
  • addLast(E e):在后端插入元素,和add一樣的效果;
  • offerFirst(E e):在前端插入元素,異常處理和offer一樣;
  • offerLast(E e):在后端插入元素,和offer一樣的效果;
  • removeFirst():移除前端的一個元素,異常處理和remove一樣;
  • removeLast():移除后端的一個元素,和remove一樣的效果;
  • pollFirst():移除前端的一個元素,和poll一樣的效果;
  • pollLast():移除后端的一個元素,異常處理和poll一樣;
  • getFirst():獲取前端的一個元素,和element一樣的效果;
  • getLast():獲取后端的一個元素,異常處理和element一樣;
  • peekFirst():獲取前端的一個元素,和peek一樣的效果;
  • peekLast():獲取后端的一個元素,異常處理和peek一樣;
  • removeFirstOccurrence(Object o):從前端開始移除第一個是o的元素;
  • removeLastOccurrence(Object o):從后端開始移除第一個是o的元素;
  • push(E e):和addFirst一樣的效果;
  • pop():和removeFirst一樣的效果。

可以發(fā)現(xiàn),其實很多方法的效果都是一樣的,只不過名字不同。比如Deque為了實現(xiàn)Stack的語義,定義了push和pop兩個方法。

BlockingQueue阻塞隊列

BlockingQueue(阻塞隊列),在Queue的基礎(chǔ)上實現(xiàn)了阻塞等待的功能。它是JDK 1.5中加入的接口,它是指這樣的一個隊列:當(dāng)生產(chǎn)者向隊列添加元素但隊列已滿時,生產(chǎn)者會被阻塞;當(dāng)消費者從隊列移除元素但隊列為空時,消費者會被阻塞。

BlockingQueue ,是java.util.concurrent 包提供的用于解決并發(fā) 生產(chǎn)者 — 消費者 問題的最有用的類,很好的解決了多線程中,如何高效安全“傳輸”數(shù)據(jù)的問題。它的特性是在任意時刻只有一個線程可以進(jìn)行take或者put操作,并且 BlockingQueue 提供類超時 return null 的機(jī)制,在許多生產(chǎn)場景里都可以看到這個工具的身影。

總體認(rèn)識

一般我們用到的阻塞隊列有哪些?可以通過下面一個類圖來總體看下:


可以看到 BlockingQueue 是一個接口,繼承它的另外還有兩個接口 BlockingDeque(雙端隊列)、TransferQueue(兩個線程之間傳遞元素)。

阻塞隊列的成員如下:


隊列類型

  1. 無限隊列(unbounded queue)— 幾乎可以無限增長
  2. 有限隊列(bounded queue)— 定義了最大容量

隊列數(shù)據(jù)結(jié)構(gòu)

隊列實質(zhì)就是一種存儲數(shù)據(jù)的結(jié)構(gòu)

  • 通常用鏈表或者數(shù)組實現(xiàn)
  • 一般而言隊列具備FIFO先進(jìn)先出的特性,當(dāng)然也有雙端隊列(Deque)優(yōu)先級隊列
  • 主要操作:入隊(Enqueue)與 出對(Dequeue)

常見的5種阻塞隊列

  • ArrayBlockingQueue:一個由數(shù)組結(jié)構(gòu)組成的有界阻塞隊列。
  • LinkedBlockingQueue:一個由鏈表結(jié)構(gòu)組成的有界阻塞隊列。
  • PriorityBlockingQueue:一個支持優(yōu)先級排序的無界阻塞隊列。
  • SynchronousQueue:一個不存儲元素的阻塞隊列。
  • DelayQueue:一個使用優(yōu)先級隊列實現(xiàn)的無界阻塞隊列。

BlockingQueue API

BlockingQueue的核心方法

  1. public interface BlockingQueue<E> extends Queue<E> { 
  2.  
  3.     //將給定元素設(shè)置到隊列中,如果設(shè)置成功返回true, 否則返回false。如果是往限定了長度的隊列中設(shè)置值,推薦使用offer()方法。 
  4.     boolean add(E e); 
  5.  
  6.     //將給定的元素設(shè)置到隊列中,如果設(shè)置成功返回true, 否則返回false. e的值不能為空,否則拋出空指針異常。 
  7.     boolean offer(E e); 
  8.  
  9.     //將元素設(shè)置到隊列中,如果隊列中沒有多余的空間,該方法會一直阻塞,直到隊列中有多余的空間。 
  10.     void put(E e) throws InterruptedException; 
  11.  
  12.     //將給定元素在給定的時間內(nèi)設(shè)置到隊列中,如果設(shè)置成功返回true, 否則返回false
  13.     boolean offer(E e, long timeout, TimeUnit unit) 
  14.         throws InterruptedException; 
  15.  
  16.     //從隊列中獲取值,如果隊列中沒有值,線程會一直阻塞,直到隊列中有值,并且該方法取得了該值。 
  17.     E take() throws InterruptedException; 
  18.  
  19.     //在給定的時間里,從隊列中獲取值,時間到了直接調(diào)用普通的poll方法,為null則直接返回null。 
  20.     E poll(long timeout, TimeUnit unit) 
  21.         throws InterruptedException; 
  22.  
  23.     //獲取隊列中剩余的空間。 
  24.     int remainingCapacity(); 
  25.  
  26.     //從隊列中移除指定的值。 
  27.     boolean remove(Object o); 
  28.  
  29.     //判斷隊列中是否擁有該值。 
  30.     public boolean contains(Object o); 
  31.  
  32.     //將隊列中值,全部移除,并發(fā)設(shè)置到給定的集合中。 
  33.     int drainTo(Collection<? super E> c); 
  34.  
  35.     //指定最多數(shù)量限制將隊列中值,全部移除,并發(fā)設(shè)置到給定的集合中。 
  36.     int drainTo(Collection<? super E> c, int maxElements); 

 BlockingQueue 接口的所有方法可以分為兩大類:負(fù)責(zé)向隊列添加元素的方法和 檢索這些元素的方法。在隊列滿/空的情況下,來自這兩個組的每個方法的行為都不同。

添加元素


檢索元素 


BlockingQueue最重要的也就是關(guān)于阻塞等待的幾個方法,而這幾個方法正好可以用來實現(xiàn)生產(chǎn)-消費的模型。

ArrayBlockingQueue

ArrayBlockingQueue 由數(shù)組支持的有界阻塞隊列,隊列基于數(shù)組實現(xiàn),容量大小在創(chuàng)建 ArrayBlockingQueue 對象時已經(jīng)定義好。 此隊列按照先進(jìn)先出(FIFO)的原則對元素進(jìn)行排序。支持公平鎖和非公平鎖,默認(rèn)采用非公平鎖。

ArrayBlockingQueue 內(nèi)部由ReentrantLock來實現(xiàn)線程安全,由Condition的await和signal來實現(xiàn)等待喚醒的功能。它的數(shù)據(jù)結(jié)構(gòu)是數(shù)組,準(zhǔn)確的說是一個循環(huán)數(shù)組(可以類比一個圓環(huán)),所有的下標(biāo)在到達(dá)最大長度時自動從0繼續(xù)開始。

深入理解ArrayBlockingQueue可以閱讀《阻塞隊列 — ArrayBlockingQueue源碼分析》


LinkedBlockingQueue

LinkedBlockingQueue 由鏈表節(jié)點支持的可選有界隊列,是一個基于鏈表的無界隊列(理論上有界),隊列按照先進(jìn)先出的順序進(jìn)行排序。LinkedBlockingQueue不同于ArrayBlockingQueue,它如果不指定容量,默認(rèn)為 Integer.MAX_VALUE,也就是無界隊列。所以為了避免隊列過大造成機(jī)器負(fù)載或者內(nèi)存爆滿的情況出現(xiàn),我們在使用的時候建議手動傳一個隊列的大小。

LinkedBlockingQueue 內(nèi)部由單鏈表實現(xiàn),只能從head取元素,從tail添加元素。添加元素和獲取元素都有獨立的鎖,也就是說LinkedBlockingQueue是讀寫分離的,讀寫操作可以并行執(zhí)行。LinkedBlockingQueue采用可重入鎖(ReentrantLock)來保證在并發(fā)情況下的線程安全。

向無限隊列添加元素的所有操作都將永遠(yuǎn)不會阻塞,[注意這里不是說不會加鎖保證線程安全],因此它可以增長到非常大的容量。

使用無限 BlockingQueue 設(shè)計生產(chǎn)者 - 消費者模型時最重要的是 消費者應(yīng)該能夠像生產(chǎn)者向隊列添加消息一樣快地消費消息。否則,內(nèi)存可能會填滿,然后就會得到一個 OutOfMemory 異常。

深入理解LinkedBlockingQueue可以閱讀《阻塞隊列 — LinkedBlockingQueue源碼分析》


PriorityBlockingQueue

PriorityBlockingQueue 優(yōu)先級隊列,線程安全(添加、讀取都進(jìn)行了加鎖)、無界、讀阻塞的隊列,底層采用的堆結(jié)構(gòu)實現(xiàn)(二叉樹),默認(rèn)是小根堆,最小的或者最大的元素會一直置頂,每次獲取都取最頂端的數(shù)據(jù)。可以實現(xiàn)優(yōu)先出隊。最特別的是它只有一個鎖,入隊操作永遠(yuǎn)成功,而出隊只有在空隊列的時候才會進(jìn)行線程阻塞。可以說有一定的應(yīng)用場景吧,比如:有任務(wù)要執(zhí)行,可以對任務(wù)加一個優(yōu)先級的權(quán)重,這樣隊列會識別出來,對該任務(wù)優(yōu)先進(jìn)行出隊。

深入理解PriorityBlockingQueue可以閱讀《阻塞隊列 —PriorityBlockingQueue源碼分析》


DelayQueue

DelayQueue 由優(yōu)先級支持的、基于時間的調(diào)度隊列,內(nèi)部使用非線程安全的優(yōu)先隊列(PriorityQueue)實現(xiàn),而無界隊列基于數(shù)組的擴(kuò)容實現(xiàn)。在創(chuàng)建元素時,可以指定多久才能從隊列中獲取當(dāng)前元素。只有延時期滿后才能從隊列中獲取元素。

深入理解DelayQueue可以閱讀《阻塞隊列 — DelayQueue源碼分析》

SynchronousQueue

SynchronousQueue 一個不存儲元素的阻塞隊列,每一個 put 操作必須等待 take 操作,否則不能繼續(xù)添加元素。支持公平鎖和非公平鎖2種策略來訪問隊列。默認(rèn)是采用非公平性策略訪問隊列。公平性策略底層使用了類似隊列的數(shù)據(jù)結(jié)構(gòu),而非公平策略底層使用了類似棧的數(shù)據(jù)結(jié)構(gòu)。SynchronousQueue的吞吐量高于LinkedBlockingQueue和ArrayBlockingQueue。

深入理解SynchronousQueue可以閱讀《阻塞隊列 — SynchronousQueue源碼分析》


LinkedTransferQueue

LinkedTransferQueue 是一個由鏈表結(jié)構(gòu)組成的無界阻塞傳輸隊列,它是一個很多隊列的結(jié)合體(ConcurrentLinkedQueue,LinkedBlockingQueue,SynchronousQueue),在除了有基本阻塞隊列的功能(但是這個阻塞隊列沒有使用鎖)之外;隊列實現(xiàn)了TransferQueue接口重寫了transfer 和 tryTransfer 方法,這組方法和SynchronousQueue公平模式的隊列類似,具有匹配的功能。

深入理解LinkedTransferQueue可以閱讀《阻塞隊列 — LinkedTransferQueue源碼分析》


LinkedBlockingDeque

LinkedBlockingDeque 一個由于鏈表結(jié)構(gòu)組成的雙向阻塞隊列,隊列頭部和尾部都可以添加和移除元素,多線程并發(fā)時,可以將鎖的競爭對多降到一半。

深入理解LinkedBlockingDeque可以閱讀《阻塞隊列 — LinkedBlockingDeque源碼分析》


DelayedWorkQueue

DelayedWorkQueue 也是一種設(shè)計為定時任務(wù)的延遲隊列,其實現(xiàn)原理和DelayQueue 基本一樣,核心數(shù)據(jù)結(jié)構(gòu)是二叉最小堆的優(yōu)先隊列,隊列滿時會自動擴(kuò)容,不過是將優(yōu)先級隊列和DelayQueue的實現(xiàn)過程遷移到本身方法體中,從而可以在該過程當(dāng)中靈活的加入定時任務(wù)特有的方法調(diào)用。

深入理解DelayedWorkQueue可以閱讀《阻塞隊列 — DelayedWorkQueue源碼分析》


對比分析

LinkedBlockingQueue與ArrayBlockingQueue區(qū)別

  • 隊列大小有所不同,ArrayBlockingQueue是有界的初始化必須指定大小,而LinkedBlockingQueue可以是有界的也可以是無界的(Integer.MAX_VALUE),對于后者而言,當(dāng)添加速度大于移除速度時,在無界的情況下,可能會造成內(nèi)存溢出等問題。
  • 數(shù)據(jù)存儲容器不同,ArrayBlockingQueue采用的是數(shù)組作為數(shù)據(jù)存儲容器,而LinkedBlockingQueue采用的則是以Node節(jié)點作為連接對象的鏈表。
  • 由于ArrayBlockingQueue采用的是數(shù)組的存儲容器,因此在插入或刪除元素時不會產(chǎn)生或銷毀任何額外的對象實例,而LinkedBlockingQueue則會生成一個額外的Node對象。這可能在長時間內(nèi)需要高效并發(fā)地處理大批量數(shù)據(jù)的時,對于GC可能存在較大影響。
  • 兩者的實現(xiàn)隊列添加或移除的鎖不一樣,ArrayBlockingQueue實現(xiàn)的隊列中的鎖是沒有分離的,即添加操作和移除操作采用的同一個ReenterLock鎖,而LinkedBlockingQueue實現(xiàn)的隊列中的鎖是分離的,其添加采用的是putLock,移除采用的則是takeLock,這樣能大大提高隊列的吞吐量,也意味著在高并發(fā)的情況下生產(chǎn)者和消費者可以并行地操作隊列中的數(shù)據(jù),以此來提高整個隊列的并發(fā)性能。

LinkedTransferQueue和SynchronousQueue(公平模式)區(qū)別

  • LinkedTransferQueue 和SynchronousQueue 其實基本是差不多的,兩者都是無鎖帶阻塞功能的隊列,都是使用的雙重隊列;
  • SynchronousQueue 通過內(nèi)部類Transferer 來實現(xiàn)公平和非公平隊列,在LinkedTransferQueue 中沒有公平與非公平的區(qū)分;
  • LinkedTransferQueue 實現(xiàn)了TransferQueue接口,該接口定義的是帶阻塞操作的操作,相比SynchronousQueue 中的Transferer 功能更豐富。
  • SynchronousQueue 中放數(shù)據(jù)操作和取數(shù)據(jù)操作都是阻塞的,當(dāng)隊列中的操作和本次操作不匹配時,線程會阻塞,直到匹配的操作到來。LinkedTransferQueue 是無界隊列,放數(shù)據(jù)操作不會阻塞,取數(shù)據(jù)操作如果沒有匹配操作可能會阻塞,通過參數(shù)決定是否阻塞(ASYNC,SYNC,NOW,TIMED)。

LinkedBlockingDeque與LinkedList區(qū)別

  1. package com.niuh.deque; 
  2.  
  3. import java.util.Iterator; 
  4. import java.util.LinkedList; 
  5. import java.util.Queue; 
  6. import java.util.concurrent.LinkedBlockingDeque; 
  7.  
  8. /* 
  9.  *   LinkedBlockingDeque是“線程安全”的隊列,而LinkedList是非線程安全的。 
  10.  * 
  11.  *   下面是“多個線程同時操作并且遍歷queue”的示例 
  12.  *   (1) 當(dāng)queue是LinkedBlockingDeque對象時,程序能正常運(yùn)行。 
  13.  *   (2) 當(dāng)queue是LinkedList對象時,程序會產(chǎn)生ConcurrentModificationException異常。 
  14.  * 
  15.  */ 
  16. public class LinkedBlockingDequeRunner { 
  17.  
  18.     // TODO: queue是LinkedList對象時,程序會出錯。 
  19.     // private static Queue<String> queue = new LinkedList<String>(); 
  20.     private static Queue<String> queue = new LinkedBlockingDeque<String>(); 
  21.  
  22.     public static void main(String[] args) { 
  23.  
  24.         // 同時啟動兩個線程對queue進(jìn)行操作! 
  25.         new MyThread("A").start(); 
  26.         new MyThread("B").start(); 
  27.     } 
  28.  
  29.     private static void printAll() { 
  30.         String value; 
  31.         Iterator iter = queue.iterator(); 
  32.         while (iter.hasNext()) { 
  33.             value = (String) iter.next(); 
  34.             System.out.print(value + ", "); 
  35.         } 
  36.         System.out.println(); 
  37.     } 
  38.  
  39.     private static class MyThread extends Thread { 
  40.         MyThread(String name) { 
  41.             super(name); 
  42.         } 
  43.  
  44.         @Override 
  45.         public void run() { 
  46.             int i = 0; 
  47.             while (i++ < 6) { 
  48.                 // “線程名” + "-" + "序號" 
  49.                 String val = Thread.currentThread().getName() + i; 
  50.                 queue.add(val); 
  51.                 // 通過“Iterator”遍歷queue。 
  52.                 printAll(); 
  53.             } 
  54.         } 
  55.     } 

 輸出結(jié)果: 

  1. A1,  
  2. A1, A2,  
  3. A1, A2, A3,  
  4. A1, A2, A3, A4,  
  5. A1, A2, A3, A4, A5,  
  6. A1, A2, A3, A4, A5, A6,  
  7. A1, A2, A3, A4, A5, A6, B1,  
  8. A1, A2, A3, A4, A5, A6, B1, B2,  
  9. A1, A2, A3, A4, A5, A6, B1, B2, B3,  
  10. A1, A2, A3, A4, A5, A6, B1, B2, B3, B4,  
  11. A1, A2, A3, A4, A5, A6, B1, B2, B3, B4, B5,  
  12. A1, A2, A3, A4, A5, A6, B1, B2, B3, B4, B5, B6,  

 結(jié)果說明:示例程序中,啟動兩個線程(線程A和線程B)分別對LinkedBlockingDeque進(jìn)行操作:

以線程A而言,它會先獲取“線程名”+“序號”,然后將該字符串添加到LinkedBlockingDeque中;

接著,遍歷并輸出LinkedBlockingDeque中的全部元素。

線程B的操作和線程A一樣,只不過線程B的名字和線程A的名字不同。

當(dāng)queue是LinkedBlockingDeque對象時,程序能正常運(yùn)行。

如果將queue改為LinkedList時,程序會產(chǎn)生ConcurrentModificationException異常。

BlockingQueue應(yīng)用

多線程生產(chǎn)者-消費者示例

接下來我們創(chuàng)建一個由兩部分組成的程序: 生產(chǎn)者 ( Producer ) 和消費者 ( Consumer ) 。

生產(chǎn)者(Producer)

生產(chǎn)者將生成一個 0 到 100 的隨機(jī)數(shù)(十全大補(bǔ)丸的編號),并將該數(shù)字放在 BlockingQueue 中。我們將創(chuàng)建 16 個線程(潘金蓮)用于生成隨機(jī)數(shù)并使用 put() 方法阻塞,直到隊列中有可用空間。

需要記住的重要一點是,我們需要阻止我們的消費者線程無限期地等待元素出現(xiàn)在隊列中。

從生產(chǎn)者(潘金蓮)向消費者(武大郎)發(fā)出信號的好方法是,不需要處理消息,而是發(fā)送稱為毒 ( poison ) 丸 ( pill ) 的特殊消息。 我們需要發(fā)送盡可能多的毒 ( poison ) 丸 ( pill ) ,因為我們有消費者(武大郎)。然后當(dāng)消費者從隊列中獲取特殊的毒 ( poison ) 丸 ( pill )消息時,它將優(yōu)雅地完成執(zhí)行。

以下生產(chǎn)者的代碼:

  1. package com.niuh.queue; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4.  
  5. import java.util.concurrent.BlockingQueue; 
  6. import java.util.concurrent.ThreadLocalRandom; 
  7.  
  8. /** 
  9.  * 生產(chǎn)者(Producer) 
  10.  **/ 
  11. @Slf4j 
  12. public class NumbersProducer implements Runnable { 
  13.     private BlockingQueue<Integer> numbersQueue; 
  14.     private final int poisonPill; 
  15.     private final int poisonPillPerProducer; 
  16.  
  17.     public NumbersProducer(BlockingQueue<Integer> numbersQueue, int poisonPill, int poisonPillPerProducer) { 
  18.         this.numbersQueue = numbersQueue; 
  19.         this.poisonPill = poisonPill; 
  20.         this.poisonPillPerProducer = poisonPillPerProducer; 
  21.     } 
  22.  
  23.     public void run() { 
  24.         try { 
  25.             generateNumbers(); 
  26.         } catch (InterruptedException e) { 
  27.             Thread.currentThread().interrupt(); 
  28.         } 
  29.     } 
  30.  
  31.     private void generateNumbers() throws InterruptedException { 
  32.         for (int i = 0; i < 100; i++) { 
  33.             numbersQueue.put(ThreadLocalRandom.current().nextInt(100)); 
  34.             log.info("潘金蓮-{}號,給武大郎的泡藥!", Thread.currentThread().getId()); 
  35.         } 
  36.  
  37.         /*while (true) { 
  38.             numbersQueue.put(ThreadLocalRandom.current().nextInt(100)); 
  39.             if (false) { 
  40.                 break; 
  41.             } 
  42.         }*/ 
  43.  
  44.         for (int j = 0; j < poisonPillPerProducer; j++) { 
  45.             numbersQueue.put(poisonPill); 
  46.             log.info("潘金蓮-{}號,往武大郎的藥里放入第{}顆毒丸!", Thread.currentThread().getId(), j + 1); 
  47.         } 
  48.     } 

 我們的生成器構(gòu)造函數(shù)將 BlockingQueue 作為參數(shù),用于協(xié)調(diào)生產(chǎn)者和使用者之間的處理,我們看到方法generateNumbers() 將 100 個元素(生產(chǎn)100副藥給武大郎吃)放入隊列中。它還需要有毒 ( poison ) 丸 ( pill ) (潘金蓮給武大郎下毒)消息,以便知道在執(zhí)行完成時放入隊列的消息類型。該消息需要將 poisonPillPerProducer 次放入隊列中。

消費者(Consumer)

每個消費者將使用 take() 方法從 BlockingQueue 獲取一個元素,因此它將阻塞,直到隊列中有一個元素。從隊列中取出一個 Integer 后,它會檢查該消息是否是毒 ( poison ) 丸 ( pill )(武大郎看潘金蓮有沒有下毒) ,如果是,則完成一個線程的執(zhí)行。否則,它將在標(biāo)準(zhǔn)輸出上打印出結(jié)果以及當(dāng)前線程的名稱。

  1. package com.niuh.queue; 
  2.  
  3. import lombok.extern.slf4j.Slf4j; 
  4.  
  5. import java.util.concurrent.BlockingQueue; 
  6.  
  7. /** 
  8.  * 消費者(Consumer) 
  9.  **/ 
  10. @Slf4j 
  11. public class NumbersConsumer implements Runnable { 
  12.     private BlockingQueue<Integer> queue; 
  13.     private final int poisonPill; 
  14.  
  15.     public NumbersConsumer(BlockingQueue<Integer> queue, int poisonPill) { 
  16.         this.queue = queue; 
  17.         this.poisonPill = poisonPill; 
  18.     } 
  19.  
  20.     public void run() { 
  21.         try { 
  22.             while (true) { 
  23.                 Integer number = queue.take(); 
  24.                 if (number.equals(poisonPill)) { 
  25.                     return
  26.                 } 
  27.                 log.info("武大郎-{}號,喝藥-編號:{}", Thread.currentThread().getId(), number); 
  28.             } 
  29.         } catch (InterruptedException e) { 
  30.             Thread.currentThread().interrupt(); 
  31.         } 
  32.     } 

 需要注意的重要事項是隊列的使用。與生成器構(gòu)造函數(shù)中的相同,隊列作為參數(shù)傳遞。我們可以這樣做,是因為 BlockingQueue 可以在線程之間共享而無需任何顯示同步。

驗證測試

既然我們有生產(chǎn)者和消費者,我們就可以開始我們的計劃。我們需要定義隊列的容量,并將其設(shè)置為 10個元素。 我們創(chuàng)建4 個生產(chǎn)者線程,并且創(chuàng)建等于可用處理器數(shù)量的消費者線程:

  1. package com.niuh.queue; 
  2.  
  3. import java.util.concurrent.ArrayBlockingQueue; 
  4. import java.util.concurrent.BlockingQueue; 
  5. import java.util.concurrent.LinkedBlockingQueue; 
  6.  
  7. /** 
  8.  * 多線程生產(chǎn)者-消費者示例 
  9.  **/ 
  10. public class Main { 
  11.  
  12.     public static void main(String[] args) { 
  13.         int BOUND = 10; 
  14.         int N_PRODUCERS = 16; 
  15.         int N_CONSUMERS = Runtime.getRuntime().availableProcessors(); //=8 
  16.         int poisonPill = Integer.MAX_VALUE; 
  17.         int poisonPillPerProducer = N_CONSUMERS / N_PRODUCERS; // =0 
  18.         int mod = N_CONSUMERS % N_PRODUCERS;//0+8=8 
  19.  
  20.         BlockingQueue<Integer> queue = new ArrayBlockingQueue<Integer>(BOUND); 
  21.  
  22.         //潘金蓮給武大郎熬藥 
  23.         for (int i = 1; i < N_PRODUCERS; i++) { 
  24.             new Thread(new NumbersProducer(queue, poisonPill, poisonPillPerProducer)).start(); 
  25.         } 
  26.  
  27.         //武大郎開始喝藥 
  28.         for (int j = 0; j < N_CONSUMERS; j++) { 
  29.             new Thread(new NumbersConsumer(queue, poisonPill)).start(); 
  30.         } 
  31.  
  32.         try { 
  33.             Thread.sleep(5000); 
  34.         } catch (InterruptedException e) { 
  35.             e.printStackTrace(); 
  36.         } 
  37.  
  38.         //潘金蓮開始投毒,武大郎喝完毒藥GG 
  39.         new Thread(new NumbersProducer(queue, poisonPill, poisonPillPerProducer + mod)).start(); 
  40.     } 
  41.  

 BlockingQueue 是使用具有容量的構(gòu)造創(chuàng)建的。我們正在創(chuàng)造 4 個生產(chǎn)者和 N 個消費者(武大郎)。我們將我們的毒 ( poison ) 丸 ( pill )消息指定為 Integer.MAX_VALUE,因為我們的生產(chǎn)者在正常工作條件下永遠(yuǎn)不會發(fā)送這樣的值。這里要注意的最重要的事情是 BlockingQueue 用于協(xié)調(diào)它們之間的工作。

PS:以上代碼提交在 Github :

https://github.com/Niuh-Study/niuh-juc-final.git

 

責(zé)任編輯:姜華 來源: 今日頭條
相關(guān)推薦

2020-07-07 07:37:36

Integer源碼Java

2025-01-14 00:00:00

Blocking隊列元素

2022-09-04 12:43:03

算法裁員Meta

2021-07-05 18:05:40

SpringBean方法

2022-02-14 12:04:43

前綴SpringJpa

2019-09-18 15:20:16

MyBatisSQL數(shù)據(jù)庫

2019-06-14 08:48:46

Tomcat日志SpringBoot

2020-11-03 06:57:10

MyBatis數(shù)據(jù)庫

2015-07-20 15:26:56

WiFi感知

2022-06-22 12:54:58

人工智能機(jī)器人元宇宙

2021-06-07 14:05:53

物聯(lián)網(wǎng)IOT物聯(lián)網(wǎng)技術(shù)

2021-12-08 08:30:55

Java AQS機(jī)制 Java 基礎(chǔ)

2023-06-30 08:27:20

2021-03-18 14:35:36

爬蟲技術(shù)開發(fā)

2021-07-08 09:17:07

物聯(lián)網(wǎng)人工智能IoT

2020-10-12 13:37:19

安全黑客技術(shù)

2019-09-16 13:51:34

物聯(lián)網(wǎng)平臺物聯(lián)網(wǎng)IOT

2009-06-15 14:15:07

Java設(shè)計模式Java

2012-01-10 14:43:48

程序員

2011-04-15 10:03:57

點贊
收藏

51CTO技術(shù)棧公眾號

无码人妻精品一区二区三区不卡 | 中文字幕在线视频网站| av午夜一区麻豆| 国产精品mp4| 国产成人av免费在线观看| 北条麻妃一区二区三区在线| 色综合久久天天| 午夜探花在线观看| 色就是色亚洲色图| 精品无码三级在线观看视频| 97久久久免费福利网址| 欧美一级特黄高清视频| 精品成人自拍视频| 欧美精品久久99久久在免费线| 国产手机免费视频| 老司机午夜在线视频| 97久久人人超碰| 亚洲永久免费观看| 国产天堂第一区| 亚洲美女黄色| 日韩视频一区在线| 国产 欧美 在线| 一区二区三区视频免费视频观看网站 | 丝袜美腿一区| 亚洲va欧美va国产va天堂影院| 五月天国产一区| 亚洲欧美自偷自拍| 成人久久18免费网站麻豆| 国产在线拍偷自揄拍精品| 亚洲影院在线播放| 影音先锋在线一区| 久久国产精品久久久久| 国产wwwwxxxx| 欧美视频免费| 国产亚洲激情在线| 国产三级视频网站| 欧美aaaaaaaa牛牛影院| 精品粉嫩aⅴ一区二区三区四区| 中文字幕 欧美日韩| 成人看片网页| 欧美午夜理伦三级在线观看| 国产最新免费视频| 福利在线免费视频| 亚洲国产视频在线| a级片一区二区| 91网在线看| 亚洲精品中文在线影院| 欧美三级午夜理伦三级老人| 999国产在线视频| 国产日产欧美一区二区视频| 欧美一区激情视频在线观看| 能在线看的av| 国产亚洲1区2区3区| 欧美资源一区| 成人免费黄色网页| 国产精品久久午夜| 一区二区三区在线视频111 | 欧美大片免费观看| 唐朝av高清盛宴| 欧美freesex交免费视频| 久久夜色精品国产欧美乱| 一级黄色片日本| 欧美午夜不卡| 国内精品一区二区三区四区| www.国产成人| 久久久久久久波多野高潮日日| 国产精品99久久久久久www | 激情综合色综合久久| 91精品国产综合久久男男 | 中文字幕一区二区三区乱码| 国产在线更新| 亚洲线精品一区二区三区| 日韩精品一区二区在线视频 | 国产精品久久久久久av| 亚洲天堂中文字幕在线| 国产一区二区在线观看免费| 超碰97网站| 青青九九免费视频在线| 欧美激情在线一区二区三区| 日本丰满少妇黄大片在线观看| 久久亚洲导航| 色综合 综合色| 国产成人美女视频| 久久影院一区二区三区| 亚洲精品国产精品自产a区红杏吧| 在线观看福利片| 香蕉综合视频| 欧美孕妇性xx| 国产精品高潮呻吟AV无码| 成人福利电影精品一区二区在线观看| 久久精品日产第一区二区三区精品版| 国产福利小视频在线| 亚洲欧美激情小说另类| 一区二区传媒有限公司| 日本午夜精品久久久久| 亚洲第一男人天堂| 夜夜春很很躁夜夜躁| 国模大胆一区二区三区| 国产精品999| 欧美一区二不卡视频| 国产嫩草影院久久久久| 欧美一级免费播放| 韩国精品视频在线观看| 亚洲精品www| 最新一区二区三区| 久久精品导航| 国产精品手机在线| а天堂中文在线官网| 色婷婷av一区二区三区软件 | 国产精品你懂的| www.avtt| 伊人久久大香| 亚洲欧美综合图区| 国产精品第一页在线观看| 精品一区二区综合| 欧美深深色噜噜狠狠yyy| 中文字幕在线观看播放| 精品污污网站免费看| 久久久久国产精品区片区无码| 亚洲综合五月| 国产在线999| 精品三级久久久久久久电影聊斋| 一区二区三区日韩在线观看| 亚洲36d大奶网| 蜜桃视频欧美| 欧美一级免费视频| 黄色av网站免费在线观看| 亚洲欧美成aⅴ人在线观看| 丰满少妇在线观看| 国产一区日韩| 国产不卡精品视男人的天堂| 天堂av网在线| 天天色天天操综合| 丝袜熟女一区二区三区| 欧美欧美天天天天操| 亚洲自拍小视频| 超碰超碰在线| 日韩一区二区在线观看| 成熟的女同志hd| 狠狠色综合日日| 久久免费视频2| 91成人福利社区| 久久午夜a级毛片| 国产精品老熟女视频一区二区| 国产精品区一区二区三| 一道本在线免费视频| 久久电影院7| 成人精品视频在线| 91福利国产在线观看菠萝蜜| 日韩午夜激情视频| 久久高清无码视频| 成人av网站在线观看| 国产精品一区二区免费在线观看| 日韩福利视频一区| 欧美与欧洲交xxxx免费观看| 国产视频网址在线| 欧美性生活久久| 国产免费美女视频| 国产精品亚洲视频| 丝袜人妻一区二区三区| 欧美综合自拍| 国产精品久久久久久久久久久久久久 | 91sao在线观看国产| 亚洲日本香蕉视频| 欧美在线影院一区二区| 少妇高潮一区二区三区喷水| 国产中文字幕一区| 国产精品国产对白熟妇| 中日韩免视频上线全都免费| 国产精品美女主播| 福利视频在线| 亚洲精品av在线播放| 五月婷婷丁香在线| 亚洲美女屁股眼交3| 黄色网址在线视频| 日本午夜一区二区| 超碰97在线看| 天天躁日日躁狠狠躁欧美| 国产精品国产福利国产秒拍 | 91国自产精品中文字幕亚洲| 国产在线资源| 欧美变态凌虐bdsm| 日韩欧美国产另类| 伊人婷婷欧美激情| brazzers精品成人一区| 国产乱人伦偷精品视频不卡| 鲁一鲁一鲁一鲁一色| 99国产**精品****| 国产日韩欧美一区二区三区四区| 625成人欧美午夜电影| 日韩视频第一页| 欧美孕妇孕交xxⅹ孕妇交| 在线观看91av| 亚洲影院在线播放| 一区二区三区资源| 国产综合精品在线| 成人免费视频视频在线观看免费| 99热成人精品热久久66| 欧美一区影院| 日韩欧美视频第二区| 一区二区三区亚洲变态调教大结局| 欧日韩不卡在线视频| a毛片在线播放| 亚洲偷欧美偷国内偷| 黄色av免费观看| 91麻豆精品国产无毒不卡在线观看 | 国产精品偷伦视频免费观看了| 日本亚洲一区二区| 99视频在线免费播放| 欧美伊人久久| 一区二区不卡在线视频 午夜欧美不卡' | 国产精品普通话对白| 黄色网zhan| 日韩欧美视频专区| 日本一区视频在线| 日韩精品社区| 国产精品久久亚洲7777| www.欧美| 国产美女91呻吟求| 日本综合视频| 日韩av手机在线| gogo高清午夜人体在线| 欧美精品在线免费| 欧美成年黄网站色视频| 亚洲人成77777在线观看网| 黄频在线免费观看| 日韩欧美久久久| 91国在线视频| 欧美丝袜自拍制服另类| 天堂а√在线中文在线新版| 亚洲成人av在线电影| 男女性高潮免费网站| 国产精品国产三级国产a| 性高潮久久久久久久| 91麻豆成人久久精品二区三区| 欧洲熟妇的性久久久久久| 国产成人无遮挡在线视频| 亚洲第一天堂久久| 国内精品国产三级国产a久久| 天堂在线资源视频| 日本aⅴ亚洲精品中文乱码| 日韩av资源在线| 天堂久久一区二区三区| 日本成人黄色网| 日韩av一级电影| 午夜免费福利在线| 久久99精品久久久久久动态图| 欧美特级aaa| 麻豆91精品91久久久的内涵| 天天综合网日韩| 国产一区二区三区免费在线观看| 捷克做爰xxxⅹ性视频| 国产主播一区二区| www.黄色网| 99综合电影在线视频| av av在线| 久久久久久99精品| 内射毛片内射国产夫妻| 国产精品久久久久精k8| 色婷婷在线视频观看| 亚洲制服欧美中文字幕中文字幕| 欧美日韩在线国产| 午夜精品福利久久久| 天天操夜夜操视频| 欧美午夜免费电影| xxxx国产精品| 国产视频久久久| 在线视频二区| 欧美男插女视频| 国产中文在线播放| 国产精品热视频| 国产精品高清一区二区| 国产精品国产精品国产专区蜜臀ah | 久久综合九色综合欧美98| 久操视频在线观看免费| 亚洲欧美激情一区二区| 色播视频在线播放| 欧美视频在线播放| 成人久久精品人妻一区二区三区| 精品亚洲一区二区三区在线播放 | 亚洲国产成人av好男人在线观看| 欧美三级午夜理伦| 欧美日本高清视频在线观看| 黑人精品一区二区| 国产亚洲精品久久久优势| fc2ppv国产精品久久| 欧美亚洲一区在线| 嫩呦国产一区二区三区av| 欧美1o一11sex性hdhd| 久久精品青草| 日韩av资源在线| 国产aⅴ综合色| 欧美日韩国产黄色| 五月婷婷综合在线| 91亚洲欧美激情| 亚洲精品视频免费| 图片区小说区亚洲| 国产精品日韩欧美| 日韩一级电影| 草草草视频在线观看| 免费看欧美美女黄的网站| 先锋资源av在线| 自拍偷在线精品自拍偷无码专区 | 国产拍在线视频| 91精品国产91久久久久青草| 精品日韩毛片| 日韩欧美一区二| 国产成人免费视频网站| a级黄色免费视频| 色综合久久综合中文综合网| 性猛交xxxx乱大交孕妇印度| 中文字幕一区二区精品| 周于希免费高清在线观看| 国产91色在线|亚洲| 国产精品久久久久久麻豆一区软件| 日本免费黄视频| 波波电影院一区二区三区| www.av成人| 欧美日韩不卡在线| 黄色的视频在线免费观看| 97国产一区二区精品久久呦 | 九九视频精品免费| 一级片手机在线观看| 天天色天天爱天天射综合| 亚洲AV无码精品色毛片浪潮| 色婷婷av一区二区三区久久| 偷拍精品精品一区二区三区| 国产一区二区精品在线| 狠狠入ady亚洲精品经典电影| 午夜一级免费视频| 中文字幕欧美一| 国产精品欧美激情在线| 日韩一级黄色av| 青青在线精品| 一区二区在线观| 韩国v欧美v日本v亚洲v| 蜜臀av午夜精品久久| 制服.丝袜.亚洲.中文.综合| 五月香视频在线观看| 国产精品自在线| 国产精品久久久久久久久久10秀 | 91日韩在线专区| 日韩免费不卡视频| 精品成人佐山爱一区二区| 国产精品蜜臀| 久久久久欧美| 狂野欧美一区| 超碰97av在线| 欧美福利视频导航| www.久久ai| 99久久精品无码一区二区毛片| 欧美日韩日本国产亚洲在线| 国产亚洲精品成人a| 婷婷综合在线观看| 国产一区二区三区不卡在线| 国产精品日韩在线观看| 亚洲欧美色图| 欧美一级片在线免费观看| 国内自拍一区| 国产麻豆日韩| 欧美黄在线观看| 免费不卡的av| 色狠狠综合天天综合综合| 成全电影播放在线观看国语| 国产精品尤物福利片在线观看| 亚洲成人精品| 永久免费未满蜜桃| 色婷婷综合五月| 日本不卡不卡| 粉嫩av免费一区二区三区| 亚洲免费网站| 少妇视频一区二区| 精品久久人人做人人爱| 性爽视频在线| 一区二区视频在线播放| 成人黄色大片在线观看| 无码人妻精品一区二区| 美女撒尿一区二区三区| 国产精品成人自拍| 亚洲一区二区蜜桃| 亚洲激情综合网| 欧洲免费在线视频| 91免费在线视频| 国产亚洲毛片| 午夜精品福利在线视频| 亚洲国产精品久久久久秋霞不卡| 中韩乱幕日产无线码一区| 路边理发店露脸熟妇泻火| 91亚洲午夜精品久久久久久| 中文永久免费观看| 久久久亚洲国产| 日韩欧美高清在线播放| 97精品人妻一区二区三区蜜桃| 欧美性猛交xxxxxx富婆| 免费毛片在线看片免费丝瓜视频 | 一本一本大道香蕉久在线精品 | 亚洲精品一区二区口爆| 国产精品av在线| 日韩午夜免费视频| 日韩a级片在线观看|