首先 LinkedBlockingQueue 是線程安全的阻塞隊列,LinkedBlockingQueue實現的生產者和消費者模型
阻塞隊列與我們平常接觸的普通隊列(LinkedList或ArrayList等)的最大不同點,在於阻塞隊列支出阻塞添加和阻塞刪除方法。
阻塞添加:所謂的阻塞添加是指當阻塞隊列元素已滿時,隊列會阻塞加入元素的線程,直隊列元素不滿時才重新喚醒線程執行元素加入操作。
阻塞刪除:阻塞刪除是指在隊列元素爲空時,刪除隊列元素的線程將被阻塞,直到隊列不爲空再執行刪除操作(一般都會返回被刪除的元素)
BlockingQueue的核心方法:
放入數據:
offer(anObject):表示如果可能的話,將anObject加到BlockingQueue裏,即如果BlockingQueue可以容納,則返回true,否則返回false.(本方法不阻塞當前執行方法的線程)
offer(E o, long timeout, TimeUnit unit):可以設定等待的時間,如果在指定的時間內,還不能往隊列中加入BlockingQueue,則返回失敗。
put(anObject):把anObject加到BlockingQueue裏,如果BlockQueue沒有空間,則調用此方法的線程被阻斷直到BlockingQueue裏面有空間再繼續.
獲取數據:
poll(time):取走BlockingQueue裏排在首位的對象,若不能立即取出,則可以等time參數規定的時間,取不到時返回null;
poll(long timeout, TimeUnit unit):從BlockingQueue取出一個隊首的對象,如果在指定時間內,隊列一旦有數據可取,則立即返回隊列中的數據。否則知道時間超時還沒有數據可取,返回失敗。
take():取走BlockingQueue裏排在首位的對象,若BlockingQueue爲空,阻斷進入等待狀態直到BlockingQueue有新的數據被加入;
drainTo():一次性從BlockingQueue獲取所有可用的數據對象(還可以指定獲取數據的個數),通過該方法,可以提升獲取數據效率;不需要多次分批加鎖或釋放鎖。
如果不指定隊列的容量大小,也就是使用默認的Integer.MAX_VALUE,如果存在添加速度大於刪除速度時候,有可能會內存溢出(OOM)
寫法一:
生產者 Producer.java
package com.vipsoft.web.app; import java.util.concurrent.LinkedBlockingQueue; public class Producer extends Thread { //1、通過構造函數傳入阻塞隊列 public static LinkedBlockingQueue<String> queue; public Producer(LinkedBlockingQueue<String> queue) { this.queue = queue; } public void run() { int i = 0; while (true) { i++; try { String msg = "P" + i; queue.put(msg); System.out.println("我生產了 => " + msg + " 隊列數量 " + queue.size()); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Producer queue.size => " + queue.size()); e.printStackTrace(); } } } }
消費者 Consumer.java
package com.vipsoft.web.app; import java.util.concurrent.LinkedBlockingQueue; public class Consumer extends Thread { public static LinkedBlockingQueue<String> queue; public Consumer(LinkedBlockingQueue<String> queue) { this.queue = queue; } public void run() { while (true) { try { System.out.println("我消費了 => " + queue.take() + " 隊列數量 " + queue.size()); Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("Consumer queue.size() => " + queue.size()); e.printStackTrace(); } } } }
主程序
package com.vipsoft.web.app; import java.util.concurrent.LinkedBlockingQueue; public class LinkedBlockingQueueTest { public static void main(String[] args) { //1、創建一個BlockingQueue int MAX_NUM = 10; //實際使用也需要指定大小,防止OOM LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(MAX_NUM); //2、創建一個生產者,一個消費者 Producer producer = new Producer(queue); Consumer consumer = new Consumer(queue); //3、開啓兩個線程 producer.start(); consumer.start(); } }
寫法二:
package com.vipsoft.web.app; import java.util.concurrent.LinkedBlockingDeque; public class LinkedBlockingQueueTest { public static void main(String[] args) { final LinkedBlockingDeque<String> queue = new LinkedBlockingDeque<>(10); //實際使用也需要指定大小,防止OOM Runnable producerRunnable = new Runnable() { public void run() { int i = 0; while (true) { i++; try { String msg = "P" + i; queue.put(msg); System.out.println("我生產了 => " + msg + " 隊列數量 " + queue.size()); Thread.sleep(1000); } catch (InterruptedException e) { System.out.println("Producer queue.size => " + queue.size()); e.printStackTrace(); } } } }; Runnable customerRunnable = new Runnable() { public void run() { while (true) { try { System.out.println("我消費了 => " + queue.take() + " 隊列數量 " + queue.size()); Thread.sleep(3000); } catch (InterruptedException e) { System.out.println("Consumer queue.size() => " + queue.size()); e.printStackTrace(); } } } }; Thread thread1 = new Thread(producerRunnable); thread1.start(); Thread thread2 = new Thread(customerRunnable); thread2.start(); } }