Java中的ArrayBlockingQueue
ArrayBlockingQueue是一个有界的阻塞队列,在内部使用数组存储元素。该队列对元素FIFO(先进先出)进行排序。队列的开头是一直在队列中最长时间的元素。队列的尾部是最短时间位于队列中的元素。新元素的插入发生在队列的尾部,并且队列检索操作会在队列的头部获得元素。
Java中的ArrayBlockingQueue是BlockingQueue接口的实现,并且是java.util.concurrent包的一部分。
有界的阻塞队列
Java中的ArrayBlockingQueue是一个有界的阻塞队列,在内部使用固定大小的数组来保存元素。创建后,队列容量无法更改。试图将一个元素放入一个完整的队列将导致操作阻塞。试图从空队列中取出一个元素的尝试也会类似地阻塞。
ArrayBlockingQueue是线程安全的
Java ArrayBlockingQueue实现是线程安全的。该类中的所有排队方法都在内部使用ReentrantLock自动实现其效果。
ArrayBlockingQueue不允许为空
Java中的ArrayBlockingQueue不接受空元素。尝试添加,放置或者提供null时,它将引发NullPointerException。
public class ArrayBQ { public static void main(String[] args) { BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(10); try { // putting null bQueue.put(null); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
输出:
Exception in thread "main" java.lang.NullPointerException at java.base/java.util.Objects.requireNonNull(Objects.java:221) at java.base/java.util.concurrent.ArrayBlockingQueue.put(ArrayBlockingQueue.java:362) at com.theitroad.programs.ArrayBQ.main(ArrayBQ.java:12)
Java ArrayBlockingQueue构造函数
- ArrayBlockingQueue(int capacity)–创建具有给定(固定)容量和默认访问策略的ArrayBlockingQueue。
- ArrayBlockingQueue(int capacity,boolean fair)–创建具有给定(固定)容量和指定访问策略的ArrayBlockingQueue。
- ArrayBlockingQueue(int capacity,boolean fair,Collection <?extends E> c)–创建具有给定(固定)容量,指定访问策略并最初包含给定集合元素的ArrayBlockingQueue,并以集合迭代器的遍历顺序添加。
ArrayBlockingQueue Java示例
BlockingQueue实现被设计为主要用于生产者-消费者队列,因此让我们来看一个使用ArrayBlockingQueue的生产者-消费者示例。
我们将创建一个容量为1的ArrayBlockingQueue,并将put和take方法分别用于插入和检索操作。这些方法将无限期地阻塞当前线程,直到操作成功。由于队列容量为1,因此插入将被阻塞,直到队列中的元素被消耗为止。
public class ArrayBQ { public static void main(String[] args) { BlockingQueue<Integer> bQueue = new ArrayBlockingQueue<Integer>(1); // Producer new Thread(()->{ for(int i = 0; i < 5; i++){ try { bQueue.put(i); System.out.println("Added to queue-" + i); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); // Consumer new Thread(()->{ for(int i = 0; i < 5; i++){ try { System.out.println("Consumer retrieved- " + bQueue.take()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }).start(); } }
输出:
Added to queue-0 Consumer retrieved- 0 Added to queue-1 Consumer retrieved- 1 Added to queue-2 Consumer retrieved- 2 Added to queue-3 Consumer retrieved- 3 Added to queue-4 Consumer retrieved- 4
ArrayBlockingQueue类方法
在ArrayBlockingQueue之类的BlockingQueue实现中,方法有四种形式,它们以不同的方式处理操作,这些操作无法立即满足,但将来可能会满足:一种抛出异常,第二种返回特殊值(null或者null false,取决于操作),第三个命令会无限期地阻塞当前线程,直到操作成功为止;第四个命令则在给定的最大时限之前放弃操作。
插入方式
- add(E e)–如果可以在不超出队列容量的情况下立即执行此操作,则在此队列的末尾插入指定的元素,如果成功,则返回true,如果队列已满,则抛出IllegalStateException。
- offer(E e)–在不超出队列容量的情况下,可以立即在队列的尾部插入指定的元素,如果成功,则返回true;如果队列已满,则返回false。
- put(E e)–将指定的元素插入此队列的末尾,如果队列已满,则等待空间变为可用。
- offer(E e,long timeout,TimeUnit unit)–将指定的元素插入此队列的末尾,直到队列满时才等待指定的等待时间以使空间变得可用。
清除方法
- remove()–检索并删除此队列的头。如果此队列为空,则抛出NoSuchElementException。
- poll()–检索并删除此队列的头部,如果此队列为空,则返回null。
- take()–检索并删除此队列的头部,如有必要,请等待直到元素可用。
- poll(long timeout,TimeUnit unit)–检索并删除此队列的头,如果有必要使元素可用,则等待指定的等待时间。
检查队列
- element()–检索但不删除此队列的头。如果此队列为空,则抛出NoSuchElementException。
- peek()–检索但不删除此队列的头,如果此队列为空,则返回null。
其他重要方法清单
- clear()–以原子方式从此队列中删除所有元素。
- contains(Object o)–如果此队列包含指定的元素,则返回true。
- iterator()–以适当的顺序返回对该队列中的元素进行迭代的迭代器。
- remove(Object o)–从此队列中删除指定元素的单个实例(如果存在)。 size()-返回此队列中的元素数。
- toArray()–按正确顺序返回包含此队列中所有元素的数组。
关于ArrayBlockingQueue的要点
- ArrayBlockingQueue是有界的阻塞队列。
- ArrayBlockingQueue内部使用固定大小的数组来保存元素。
- Java中的ArrayBlockingQueue以FIFO(先进先出)顺序对元素进行排序。
- 在ArrayBlockingQueue中,新元素的插入发生在队列的尾部,而元素的检索则发生在队列的头部。
- ArrayBlockingQueue不允许使用null元素。
- ArrayBlockingQueue类支持可选的公平性策略,用于订购等待的生产者线程和使用者线程。如果公平性设置为true,则按FIFO顺序授予线程访问权限。
- ArrayBlockingQueue是线程安全的。它使用ReentrantLock来保护所有访问。