BlockingQueue阻塞佇列
- 1.BlockingQueue介紹
- 1.1.引言:
- 1.2.阻塞佇列介紹:
- 1.3.阻塞佇列的用處:
- 1.4.介面架構圖
- 2.BlockingQueue核心方法
- 3.BlockingQueue案例測驗
- 3.1.拋出例外的方法代碼驗證:
- 3.2.回傳特殊值的方法(boolean值回傳)
- 3.3.阻塞佇列的方法
- 3.4.超時中斷的方法
1.BlockingQueue介紹
1.1.引言:
阻塞雖然是不好的,但是我們有時候不得不阻塞,比如說一家餐廳人滿了,店主當然不希望即將過來的這些客人全部都走,而是希望它們留下來繼續排隊等候,對于阻塞的內容,執行緒和資源的調度管理能力,這樣就出了一個介面,就叫阻塞佇列,在不得不阻塞,必須要阻塞的時候,如何管理好被阻塞的資源和執行緒,這就是阻塞佇列,
佇列的特性:先進先出,插入元素在隊尾,洗掉元素在隊頭,
1.2.阻塞佇列介紹:
阻塞:必須要阻塞/不得不阻塞
阻塞佇列是一個佇列,在資料結構中中起的作用如下圖:

執行緒1往阻塞佇列里添加元素,執行緒2從阻塞佇列里移除元素,
阻塞佇列,我們可以簡單的理解為海底撈火鍋店的候客區,如圖綠框框就是我們的阻塞佇列,即我們所理解的海底撈火鍋店的候客區,里面等著的就是一桌一桌的食客,如果候客區也滿了,還加不加人?
當佇列是空的,從佇列中獲取元素的操作將會被阻塞,
當佇列是滿的,從佇列中添加元素的操作將會被阻塞,
試圖從空的佇列中獲取元素的執行緒將會被阻塞,直到其他執行緒往空的佇列插入新的元素,
對于上面阻塞的問題,我們又可以舉一個例子,假如說Thread1是做蛋糕的師傅,Thread2是買蛋糕的顧客,而BlockingQueue是食品柜,當顧客來了,發現食品柜是空的,想消費蛋糕的操作將會被阻塞,如果蛋糕買的人少了,食品柜中的蛋糕滿了,此時生產蛋糕的操作將會被阻塞,
**試圖從空的佇列中獲取元素的執行緒將會被阻塞,直到其他執行緒往空的佇列插入新的元素,**簡單的說,就是空的時候不能消費,滿的時候不能增加,
試圖向已滿的佇列中添加新元素的執行緒將會被阻塞,直到其它執行緒從佇列中移除一個或多個元素或者完全清空,使佇列變得空閑起來并后續新增,
1.3.阻塞佇列的用處:
在多執行緒領域:所謂阻塞,在某些情況下會掛起執行緒(即阻塞),一旦條件滿足,被掛起的執行緒又會自動被喚起,
wait就是一種阻塞,notify是一種喚醒,await是一種阻塞, signal是喚醒,
為什么需要 BlockingQueue?
好處是我們不需要關心什么時候需要阻塞執行緒,什么時候需要喚醒執行緒,因為這一切BlockingQueue 都給你一手包辦了,在 concurrent 包發布以前,在多執行緒環境下,我們每個程式員都必須自己去控制這些細節,尤其還要兼顧效率和執行緒安全,而這會給我們的程式帶來不小的復雜度,
也就是不用手寫wait和notify了,只要柜子里蛋糕滿了,生產執行緒就會阻塞,只要柜子里沒有蛋糕了,消費執行緒就會被阻塞,
1.4.介面架構圖

BlockingQueue所有已知實作類:
ArrayBlockingQueue , DelayQueue , LinkedBlockingDeque , LinkedBlockingQueue , LinkedTransferQueue , PriorityBlockingQueue , SynchronousQueue
在我們以前學習集合的程序中,Collection介面有兩個常用的介面List介面和Set介面,現在又有了阻塞佇列介面BlockingQueue
ArrayBlockingQueue:由陣列結構組成的有界阻塞佇列
LinkedBlockingQueue:由鏈表結構組成的有界(但大小默認值為integer.MAX_VALUE)阻塞佇列
PriorityBlockingQueue:支持優先級排序的無界阻塞佇列
DelayQueue:使用優先級佇列實作的延遲無界阻塞佇列
SynchronousQueue:不存盤元素的阻塞佇列,也即單個元素的佇列
LinkedTransferQueue:由鏈表結構組成的無界阻塞佇列
LinkedBlockingDeque:由鏈表結構組成的雙向阻塞佇列
2.BlockingQueue核心方法
核心方法如下:
| 方法型別 | 拋出例外 | 特殊值 | 阻塞 | 超時 |
|---|---|---|---|---|
| 插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
| 移除 | remove() | poll() | take() | put(time,unit) |
| 移除 | element() | peek() | 不可用 | 不可用 |
共同點:插入成功或者洗掉成功都回傳true(除了put和take),區別在于處理例外情況
(1)拋出例外的方法
當阻塞佇列滿時,再往佇列里add元素會拋出IllegalStateException:Queue full;
當阻塞佇列空時,再從佇列里remove移除元素會拋NoSuchElementException,
(2)回傳特殊值(boolean值)的方法
插入成功,回傳true;插入失敗,回傳false;
洗掉成功回傳出佇列元素;洗掉失敗回傳null;
(3)阻塞的方法(添加無回傳值)
當阻塞佇列滿時,生產者執行緒繼續往佇列里put元素,佇列會一直阻塞生產執行緒直到put資料or回應中斷退出,
當阻塞佇列空時,消費者執行緒試圖take佇列里的元素,佇列會一直阻塞消費者執行緒直到佇列有可用元素,
(4)超時的方法
當向阻塞佇列offer元素時候,時間超過了設定的值,就會出現超時中斷;
當向阻塞佇列poll元素時候,時間超過了設定的值,就會出現超時中斷,
3.BlockingQueue案例測驗
3.1.拋出例外的方法代碼驗證:
- add方法拋出例外
public static void main(String[] args) {
//ArrayBlockingQueue是由陣列結構組成的有界阻塞佇列,所以要加引數
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("d"));
}

public static void main(String[] args) {
//ArrayBlockingQueue是由陣列結構組成的有界阻塞佇列,所以要加引數
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("d"));
}

當阻塞佇列滿時,再往佇列里add元素會拋出IllegalStateException:Queue full;
- remove方法拋出例外
public static void main(String[] args) {
//ArrayBlockingQueue是由陣列結構組成的有界阻塞佇列,所以要加引數
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("b"));
System.out.println(blockingQueue.add("c"));
//remove會回傳被移除的物件
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
System.out.println(blockingQueue.remove());
}

當阻塞佇列空時,再從佇列里remove移除元素會拋NoSuchElementException,
- element檢查方法:(底層呼叫了 peek()方法)
public static void main(String[] args) {
//ArrayBlockingQueue是由陣列結構組成的有界阻塞佇列,所以要加引數
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.add("a"));
System.out.println(blockingQueue.add("a"));
//element就是查看一下隊首元素的值
System.out.println(blockingQueue.element());
}

3.2.回傳特殊值的方法(boolean值回傳)
- 阻塞佇列offer方法的使用
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("c"));
System.out.println(blockingQueue.offer("d"));
}

插入成功,回傳true;插入失敗,回傳false;
- 阻塞佇列poll方法的使用
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("c"));
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
System.out.println(blockingQueue.poll());
}

洗掉成功回傳出佇列元素;洗掉失敗回傳null;
3.3.阻塞佇列的方法
- 阻塞佇列put方法使用
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
blockingQueue.put("a");
blockingQueue.put("a");
blockingQueue.put("a");
blockingQueue.put("a");
}

沒有報錯,當阻塞佇列滿時,生產者執行緒繼續往佇列里put元素,佇列會一直阻塞生產執行緒直到put資料or回應中斷退出,,即騰出空位置為止,能塞進去,與semaphore爭車位類似
- 阻塞佇列take方法使用
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
blockingQueue.put("a");
blockingQueue.put("a");
blockingQueue.put("a");
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
System.out.println(blockingQueue.take());
}

當阻塞佇列空時,消費者執行緒試圖take佇列里的元素,佇列會一直阻塞消費者執行緒直到佇列有可用元素,
3.4.超時中斷的方法
- 阻塞佇列offer超時中斷演示
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
}
程式執行結果如下:當往阻塞佇列添加第六個元素的時候,佇列添加不進去,3秒后會超時中斷,

當向阻塞佇列offer元素時候,時間超過了設定的值,就會出現超時中斷;
- 阻塞佇列poll超時中斷演示
public static void main(String[] args) throws InterruptedException {
BlockingQueue<String> blockingQueue=new ArrayBlockingQueue<>(3);
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("a",3L,TimeUnit.SECONDS));
System.out.println(blockingQueue.offer("a",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));
}
當向阻塞佇列poll元素時候,時間超過了設定的值,就會出現超時中斷,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/254037.html
標籤:其他
