阻塞隊列
阻塞隊列(BlockingQueue)是一個支持兩個附加操作的隊列。這兩個附加的操作支持阻塞的插入和移除方法。
阻塞隊列常用於生產者和消費者的場景:
當隊列爲空的,從隊列中獲取元素的操作將會阻塞;
當隊列爲滿的,從隊列中添加元素的操作將會阻塞;
所謂的阻塞:在某些情況下會掛起線程(即阻塞),一旦條件滿足,被掛起的線程又會自動被喚起。
阻塞隊列的用處:不需要我們關心什麼時候需要阻塞線程,什麼時候需要喚醒線程。
BlockingQueue的實現類(比較常用):
- ArrayBlockingQueue:有數組結構組成的有界阻塞隊列;
- LinkedBlockingQueue:有鏈表結構組成的有界(但大小默認值爲Integer.MAX_VALUE)阻塞隊列;
- SynchronousQueue:不存儲元素的阻塞隊列,即單個元素的隊列。
方法類型 | 拋出異常 | 布爾值 | 阻塞 | 超時 |
---|---|---|---|---|
插入 | add(e) | offer(e) | put(e) | offer(e,time,TimeUnit) |
刪除 | remove() | poll() | take() | poll(time,TimeUnit); |
檢查 | element() | peek() | 不可用 | 不可用 |
拋出異常
- 當阻塞隊列滿時,再往隊列裏add插入元素會拋出IllegalStateException:Queue full
- 當隊列爲空時,再往隊列中remove移除元素會拋NoSuchElementException
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(3);
System.out.println(queue.add("a"));
System.out.println(queue.add("a"));
System.out.println(queue.add("a"));
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
System.out.println(queue.remove());
布爾值
- 插入方法,成功未true,失敗爲false
- 移除方法,成功返回隊列的元素,隊列沒有就返回null
System.out.println(queue.offer("a"));
System.out.println(queue.offer("a"));
System.out.println(queue.offer("a"));
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
阻塞
- 當阻塞隊列滿時,生產者線程繼續往隊列裏put元素,隊列會一直阻塞生產者線程直到put數據or響應中斷退出
- 當阻塞隊列空時,消費者線程試圖從隊列裏take元素,隊列會一直阻塞消費者線程直到隊列可用
queue.put("a");
queue.put("a");
queue.put("a");
//queue.put("a");
System.out.println(queue.take());
System.out.println(queue.take());
System.out.println(queue.take());
//System.out.println(queue.take());
超時
- 當阻塞隊列滿時,隊列會阻塞生產者線程一定時間,超過限制後生產者線程會退出
queue.offer("a");
queue.offer("a");
queue.offer("a");
queue.offer("a",1L, TimeUnit.SECONDS);
System.out.println(queue.poll());
System.out.println(queue.poll());
System.out.println(queue.poll());
queue.poll(1L,TimeUnit.SECONDS);
注意:
如果是無界阻塞隊列,隊列不可能會出現滿的情況,所以使用put或offer方法永遠不會被阻塞,而且使用offer方法時,該方法永遠返回true