BlockingQueue

363 阅读3分钟

【写在前面】 所谓读源码,三分看代码,七分看注释。英语不好怎么办,我帮你翻译!

package java.util.concurrent 
public interface BlockingQueue<E>
extends Queue<E>

一个额外支持一些操作的队列,这些操作就是:等待这个队列变为非空,当要(从一个空队列)取回一个元素的时候;等待这个队列有空间可用,当要存储一个元素(到满队列)的时候。BlockingQueue的方法有四种形式,那些使用不同的处理操作的方法不能立即得到满足,但也许在未来某一时刻得到满足:第一,抛出一个异常;二,返回一个特定值(要么为null,要么为false,取决于具体操作);三,无限期的阻塞当前线程直到操作成功;四,在放弃之前最多阻塞一段给定的时间。下面这张表格概括了这些方法:

抛异常 返回特定值 阻塞 超时
插入 add(e) offer(e) put(e) offer(e, time, unit)
删除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用

一个阻塞队列不接收null元素。(这个类)实现了add,put和offer一个null元素的时候抛出NullPointerException。一个null值作为一个标记值表明poll操作的的失败。
一个阻塞队列的容量可能是有限的。在任何给定的时间内,他都有剩余容量,若超过了这个容量,那么就不能在不阻塞的情况下插入一个元素。一个阻塞队列(如果)没有内在的容量约束,那么总是表明剩余容量为Integer最大值。
阻塞队列的实现主要被设计用于生产者-消费者队列模型,但是额外地支持了Collection接口。因此,举个例子,它可能通过使用remove(x)方法从一个队列中移除一个任意元素。然而,这样的操作通常执行的不是很有效,仅供偶尔使用,比如当一个排队消息取消的时候。
阻塞队列的实现是线程安全的。所有的队列方法实现效果都会自动地使用内置的锁或者其他形式的同步控制。然而,在一个实现中,批量的集合操作addAll,containsAll,retainAll和removeAll不一定是原子操作,除非指定了其他操作。因此,举个例子,addAll(c)很可能在添加了c的一部分元素后发生失败(抛出异常)。
一个阻塞队列没有内在地支持任何类型的"close"和"shutdown"方法去表明没有更多的元素被添加。这种特性的需求与使用倾向于具体的实现。举个例子,一种常见的策略为,生产者插入特殊的流末尾或者有毒对象,当消费者使用这些对象时,这些对象将相应地进行解释。
使用范例,基于经典的生产者-消费者场景。请注意阻塞队列能够安全地被多生产者和多消费者使用。

class Producer implements Runnable {
   private final BlockingQueue queue;
   Producer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { queue.put(produce()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   Object produce() { ... }
 }

 class Consumer implements Runnable {
   private final BlockingQueue queue;
   Consumer(BlockingQueue q) { queue = q; }
   public void run() {
     try {
       while (true) { consume(queue.take()); }
     } catch (InterruptedException ex) { ... handle ...}
   }
   void consume(Object x) { ... }
 }

 class Setup {
   void main() {
     BlockingQueue q = new SomeQueueImplementation();
     Producer p = new Producer(q);
     Consumer c1 = new Consumer(q);
     Consumer c2 = new Consumer(q);
     new Thread(p).start();
     new Thread(c1).start();
     new Thread(c2).start();
   }
 }

内存一致性影响:与其他并发集合一样,一个线程放置一个对象到阻塞队列的行为发生在其他线程访问或删除这个元素之前。
这个接口是Java Collections Framework中的一员。
Since:1.5