本文內容如有錯誤、不足之處,歡迎技術愛好者們一同探討,在本文下面討論區留言,感謝。
簡述
阻塞隊列:當線程隊列是空時,從隊列中獲取元素的操作將會被阻塞;當線程隊列是滿時,往隊列裏添加元素的操作將會被阻塞。
Java 5 開始出現存在 java.util.concurrent 包下,阻塞隊列是一個隊列,當嘗試從隊列中出隊並且隊列爲空時,或者嘗試將項目入隊並且隊列已滿時,它將阻塞。嘗試從空隊列中出隊的線程被阻止,直到其他線程將一個項目插入隊列中爲止。嘗試使一個項目進入完整隊列的線程被阻塞,直到某個其他線程在隊列中騰出空間爲止,方法是使一個或多個項目出隊或完全清除隊列。
原理
原理示意圖片:
圖片地址:http://tutorials.jenkov.com/java-concurrency/blocking-queues.html
下面是一個簡單的BlockQueue的實現:
public class BlockingQueue {
private List queue = new LinkedList();
private int limit = 10;
public BlockingQueue(int limit){
this.limit = limit;
}
public synchronized void enqueue(Object item)throws InterruptedException {
while(this.queue.size() == this.limit) {
wait();
}
if(this.queue.size() == 0) {
notifyAll();
}
this.queue.add(item);
}
public synchronized Object dequeue() throws InterruptedException{
while(this.queue.size() == 0){
wait();
}
if(this.queue.size() == this.limit){
notifyAll();
}
return this.queue.remove(0);
}
}
操作代碼:
// 調用 BlockingQueue 方法的Java程序演示
import java.util.concurrent.*;
import java.util.*;
public class GFG {
public static void main(String[] args)
throws InterruptedException
{
// ArrayBlockingQueue 的邊界大小
int capacity = 5;
// 創建 ArrayBlockingQueue
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<String>(capacity);
// 使用put()方法添加元素
queue.put("StarWars");
queue.put("SuperMan");
queue.put("Flash");
queue.put("BatMan");
queue.put("Avengers");
// 打印隊列
System.out.println("queue contains "+ queue);
// 移除一些元素
queue.remove();
queue.remove();
queue.put("CaptainAmerica");
queue.put("Thor");
System.out.println("queue contains " + queue);
}
}
輸出結果:
queue contains [StarWars, SuperMan, Flash, BatMan, Avengers]
queue contains [Flash, BatMan, Avengers, CaptainAmerica, Thor]
操作
BlockingQueue方法有四種形式,它們以不同的方式處理操作,這些操作可能無法滿足開發需求,但將來可能會滿足:第一種拋出異常,第二種返回特殊值( null或false,具體取決於操作),第三個塊將無限期地阻塞當前線程,直到操作成功爲止;第四個塊僅在給定的最大時間限制內超時。
下表總結了這些方法:
方法類型 | 拋出異常 | 特殊值 | 阻塞 | 超時 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,unit) |
移除 | remove() | poll() | take() | poll(time,unit) |
檢查 | element() | peek() | 無 | 無 |
這4種不同的行爲集意味着:
- 引發異常:如果無法立即進行嘗試的操作,則會引發異常。
- 特殊值:如果無法立即嘗試操作,則會返回一個特殊值(通常爲true / false)。
- 阻塞:如果無法立即進行嘗試的操作,則該方法調用將一直阻塞直到可行爲止。
- 超時:如果無法立即進行嘗試的操作,則該方法調用將一直阻塞直到成功,但等待時間不得長於給定的超時。返回一個特殊值,告訴操作是否成功(通常爲true / false)。
下面是一個生產者消費者的案例使用BlockQueue:
class Producer implements Runnable {
private final BlockingQueue queue;
Producer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
}
Object produce() { ... }
}
class Consumer implements Runnable {
private final BlockingQueue queue;
Consumer(BlockingQueue q) { queue = q; }
public void run() {
try {
while (true) { consume(queue.take()); }
} catch (InterruptedException ex) { ... handle ...}
}
void consume(Object x) { ... }
}
class Setup {
void main() {
BlockingQueue q = new SomeQueueImplementation();
Producer p = new Producer(q);
Consumer c1 = new Consumer(q);
Consumer c2 = new Consumer(q);
new Thread(p).start();
new Thread(c1).start();
new Thread(c2).start();
}
}
參考資料
Blocking Queues
Interface BlockingQueue
Java BlockingQueue
BlockingQueue Interface in Java