Java中的LinkedBlockingQueue

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

Java中的LinkedBlockingQueue是BlockingQueue接口的实现,并且是java.util.concurrent包的一部分。 LinkedBlockingQueue具有ArrayBlockingQueue和DelayQueue的功能。 ArrayBlockingQueue是一个有界阻塞队列,其中,DelayQueue是一个无界阻塞队列。 LinkedBlockingQueue位于中间,因为它是一个可选绑定的阻塞队列,这意味着可以指定队列的容量,从而使其成为有界的,也可以不指定。

Java中的LinkedBlockingQueue

LinkedBlockingQueue基于链接的节点,其中每个节点都保留对下一个节点的引用。除非每次插入都会使队列超出容量,否则将在每次插入时动态创建链接节点。

该队列对元素FIFO(先进先出)进行排序。队列的开头是已在队列中最长时间的元素。队列的尾部是最短时间位于队列中的元素。新元素插入到队列的尾部,并且队列检索操作在队列的开头获取元素。

Java中LinkedBlockingQueue的功能

  • LinkedBlockingQueue是一个可选绑定的阻塞队列。
  • Java LinkedBlockingQueue实现是线程安全的。该类中的所有排队方法都在内部使用ReentrantLock自动实现其效果。
  • LinkedBlockingQueue不允许使用null元素。尝试添加,放置或者提供null时,它将引发NullPointerException。
public class LinkedBQ {
  public static void main(String[] args) {
    BlockingQueue bQueue = new LinkedBlockingQueue<>();
    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.concurrent.LinkedBlockingQueue.put(LinkedBlockingQueue.java:325)
	at com.theitroad.programs.LinkedBQ.main(LinkedBQ.java:12)

Java LinkedBlockingQueue构造函数

  • LinkedBlockingQueue()–创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue。
  • LinkedBlockingQueue(int Capacity)–创建具有给定(固定)容量的LinkedBlockingQueue。
  • LinkedBlockingQueue(Collection <?扩展E> c)–创建一个容量为Integer.MAX_VALUE的LinkedBlockingQueue,最初包含给定集合的元素,并以集合迭代器的遍历顺序添加。

LinkedBlockingQueue Java示例

BlockingQueue实现被设计为主要用于生产者-消费者队列,因此让我们来看一个使用LinkedBlockingQueue的生产者-消费者示例。

我们将创建一个容量为1的LinkedBlockingQueue,并分别使用put和take方法进行插入和检索操作。这些方法将无限期地阻塞当前线程,直到操作成功。由于队列容量为1,因此插入将被阻塞,直到队列中的元素被消耗为止。

public class LinkedBQ {
  public static void main(String[] args) {        
    // shared queue
    BlockingQueue<Integer> bQueue = new LinkedBlockingQueue<>(1);
    ExecutorService executor = Executors.newFixedThreadPool(2);
    executor.execute(new LinkedProducer(bQueue));
    executor.execute(new LinkedConsumer(bQueue));
    executor.shutdown();
  }
}

// Producer
class LinkedProducer implements Runnable{
  BlockingQueue<Integer> bQueue;
  LinkedProducer(BlockingQueue<Integer> bQueue){
    this.bQueue = bQueue;
  }
  @Override
  public void run() {
    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();
      }
    }
  }
}
//Consumer
class LinkedConsumer implements Runnable{
  BlockingQueue<Integer> bQueue;
  LinkedConsumer(BlockingQueue<Integer> bQueue){
    this.bQueue = bQueue;
  }
  @Override
  public void run() {
    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();
      }
    }
  }
}

输出:

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
Consumer retrieved- 4
Added to queue-4

LinkedBlockingQueue类方法

在像LinkedBlockingQueue这样的BlockingQueue实现中,用于添加和删除元素的方法有四种形式
一个抛出异常,第二个返回一个特殊值(取决于操作,为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)–检索并删除此队列的头,如果有必要使元素可用,则等待指定的等待时间。

其他重要方法清单

  • clear()–以原子方式从此队列中删除所有元素。
  • contains(Object o)–如果此队列包含指定的元素,则返回true。
  • missingCapacity()–返回此队列理想情况下(在没有内存或者资源约束的情况下)可以无阻塞接受的其他元素的数量。
  • remove(Object o)–从此队列中删除指定元素的单个实例(如果存在)。
  • size()–返回此队列中的元素数。
  • spliterator()–返回此队列中元素的分隔符。
  • toArray()–按正确顺序返回包含此队列中所有元素的数组。