Java BlockingQueue 接口

2017-06-28

BlockingQueue 接口

阻塞队列(Blocking Queue)是一种支持阻塞地插入和移除的队列。阻塞队列常用于生产者/消费者模式,生产者负责向队列中放元素,消费者负责从队列中拿元素。如果队列已满,那么队列将会阻塞生产者,直到队列不满;类似地,如果队列为空,那么队列将会阻塞消费者,直到队列不空。

BlockingQueue 接口定义如下:

public interface BlockingQueue<E> extends Queue<E> 

该接口定义了四类方法,处理那些不能立即被满足的操作:第一类抛出异常,第二类返回一个特殊值(null 或者 false,取决于操作类型),第三类会无限期阻塞当前线程直到操作成功,第四类会在指定时间内阻塞当前线程。总结如下:

方法 抛出异常 返回特殊值 一直阻塞 超时退出
插入 add(e) offer(e) put(e) offer(e, time, unit)
移除 remove() poll() take() poll(time, unit)
检查 element() peek() 不可用 不可用

阻塞队列不接受元素为 null,因为 null 值有特殊含义:poll 操作失败时将返回 null。使用 add,put 和 offer 等方法尝试插入 null 值将抛出 NullPointerException。

Java 中阻塞队列可分为有界和无界。任意时刻,对于一个有界阻塞队列,调用 remainingCapacity() 方法可以大约得知剩余容量(不可靠);对于无界队列,remainingCapacity() 则总是返回 Integer.MAX_VALUE。

注意,Java 中的阻塞队列本质上不支持任何类型的 “close” 或者 “shutdown” 操作,表示不再有元素加入到队列中。这样的功能实现通常依赖于队列使用者。一个常见的策略是生产者向队列中加入特殊的 end-of-stream 或者 poison 对象,当消费者取出这样的元素,便知道队列已经被”关闭“了。

阻塞队列能保证内存一致性:一个线程向阻塞队列放入一个元素 happens-before 另一个线程随后访问或者删除该元素。

BlockingQueue API

BlockingQueue 接口 API 如下:

add

boolean add(E e)

向阻塞队列插入指定元素 e。插入成功后,方法返回 true;如果队列已满,则抛出 IllegalStateException。

offer

boolean offer(E e)

向阻塞队列中插入元素。插入成功后,方法返回 true;否则返回 false。 另一 offer 重载方法为:

boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException

如果不能插入,此方法会等待至多 timeout 时间。插入成功后,方法返回 true;如果未能在指定时间内插入,返回 false。

put

void put(E e) throws InterruptedException

向阻塞队列中插入指定元素 e。如果队列已满,该方法会一直阻塞线程直到队列有空间能够插入。如果等待过程中,线程被中断将抛出 InterruptedException。

take

E take() throws InterruptedException

返回并删除队列头元素。如果队列为空,那么该方法会阻塞当前线程直到队列不为空。

poll

E poll(long timeout, TimeUnit unit) throws InterruptedException

返回并删除队列头元素。如果队列为空,此方法会等待至多 timeout 时间。如果超时还不能取得头元素,将返回 null。

remainingCapacity

int remainingCapacity()

返回阻塞队列理想情况(不考虑内存或者资源限制)下还能再插入的元素个数;如果是无界队列,则返回 Integer.MAX_VALUE。

注意不能通过检查 remainingCapacity 来判断是否可以插入元素,因为另一线程可能正要插入或者删除元素。

remove

boolean remove(Object o)

从阻塞队列中删除指定元素的单个实例(如果存在)。更具体的说,如果队列包含一个或者多个这样的元素 e,使得 o.equals(e),那么就删除其中一个。如果队列包含这样的元素,方法返回 true(等价地,如果队列发生了改变,那么方法也返回 true)

contains

boolean contains(Object o)

如果队列中存在至少一个元素 e,使得 o.equals(e),那么方法返回 true;否则返回 false。

drainTo

int drainTo(Collection<? super E> c)

从阻塞队列中删除所有的元素,并将它们加入到给定的集合 c 中。在操作过程中,如果有其他操作对集合 c 做修改(插入或者删除元素),那么这样的行为是未定义的。如果 c 是队列本身,则会抛出 IllegalArgumentException。

方法返回已迁移元素的数量。

该方法的另一重载版本是:

int drainTo(Collection<? super E> c, int maxElements)

从阻塞队列中删除至多 maxElements 个元素,并将它们加入到给定的集合 c 中。

参考

  1. Interface BlockingQueue