Java中的ArrayBlockingQueue

时间:2020-01-09 10:35:11  来源:igfitidea点击:

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来保护所有访问。