想必大家都很熟悉生產者-消費者隊列,生產者負責添加元素到隊列,如果隊列已滿則會進入阻塞狀態直到有消費者拿走元素。相反,消費者負責從隊列中拿走元素,如果隊列為空則會進入阻塞狀態直到有生產者添加元素到隊列。BlockingQueue就是這么一個生產者-消費者隊列。
BlockingQueue是Queue的子接口
public interface BlockingQueue<E> extends Queue<E>
BlockingQueue拿走元素時,如果隊列為空,阻塞等待會有兩種情況:
一種是一直等待直到隊列不為空,這種情況調用take方法
E take() throws InterruptedException;
另一種就是設定一個超時時間,一直等到超時,這種情況調用的是pool方法
E poll(long timeout, TimeUnit unit) throws InterruptedException;
同樣對于添加元素來說,也有兩種情況:
一直等待使用put方法
void put(E e) throws InterruptedException;
超時等待使用offer方法
boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
BlockingQueue的父接口Queue關于拿走元素的接口有兩個:remove和pool。
兩者的區別在于當隊列為空時前者會拋出NoSuchElementException,而后者返回null。
E remove();E poll();
添加元素的接口也有兩個:add和offer。兩者的區別在于當隊列為滿時前者會拋出IllegalStateException,而后者返回false。
boolean add(E e);boolean offer(E e);
一般來說Queue類型的數據結構會有兩種實現:數組和鏈表。對應到BlockingQueue就是ArrayBlockingQueue和LinkedBlockingQueue,兩者都是基于AbstractQueue實現的。
public class ArrayBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, java.io.Serializable
這里很有必要說說AbstractQueue,AbstractQueue只是實現了add和remove方法,而且很有意思的是這兩個方法都是借助他們對應的無異常版本的方法offer和pool來實現的。
public boolean add(E e) { if (offer(e)) return true; else throw new IllegalStateException("Queue full"); } public E remove() { E x = poll(); if (x != null) return x; else throw new NoSuchElementException(); }這樣做的好處無疑是提供了良好的擴展性,也就是把真正添加/拿走元素的實現留給子類來完成(可以實現線程安全和非線程安全兩個版本)。
研究BlockingQueue關注的重點就是Blocking是如果實現的,接下來的兩篇文章將會詳細分析ArrayBlockingQueue和LinkedBlockingQueue如何實現線程的Blocking。
新聞熱點
疑難解答