BlockingQueue和List 有什么区别,BlockingQueue用在什么场面和场景的区别下

并发一枝花之 BlockingQueue - ImportNew
JDK版本:oracle java 1.8.0_102
继续阅读之前,需确保你对锁和条件队列的使用方法烂熟于心,特别是条件队列,否则你可能无法理解以下源码的精妙之处,甚至基本的正确性。本篇暂不涉及此部分内容,需读者自行准备。
BlockingQueue继承自Queue,增加了阻塞的入队、出队等特性:
public interface BlockingQueue&E& extends Queue&E& {
boolean add(E e);
void put(E e) throws InterruptedE
// can extends from Queue. i don't know why overriding here
boolean offer(E e);
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedE
E take() throws InterruptedE
// extends from Queue
// E poll();
E poll(long timeout, TimeUnit unit)
throws InterruptedE
int remainingCapacity();
boolean remove(Object o);
public boolean contains(Object o);
int drainTo(Collection&? super E& c);
int drainTo(Collection&? super E& c, int maxElements);
为了方便讲解,我调整了部分方法的顺序,还增加了注释辅助说明。
需要关注的是两对方法:
阻塞方法BlockingQueue#put()和BlockingQueue#take():如果入队(或出队,下同)失败(如希望入队但队列满,下同),则等待,一直到满足入队条件,入队成功。
非阻塞方法BlockingQueue#offer()和BlockingQueue#poll(),及它们的超时版本:非超时版本是瞬时动作,如果入队当前入队失败,则立刻返回失败;超时版本可在此基础上阻塞一段时间,相当于限时的BlockingQueue#put()和BlockingQueue#take()。
BlockingQueue有很多实现类。根据github的code results排名,最常用的是LinkedBlockingQueue(253k)和ArrayBlockingQueue(95k)。LinkedBlockingQueue的性能在大部分情况下优于ArrayBlockingQueue,本文主要介绍LinkedBlockingQueue,文末会简要提及二者的对比。
LinkedBlockingQueue
阻塞方法put()和take()
两个阻塞方法相对简单,有助于理解LinkedBlockingQueue的核心思想:在队头和队尾各持有一把锁,入队和出队之间不存在竞争。
前面在Java实现生产者-消费者模型中循序渐进的引出了BlockingQueue#put()和BlockingQueue#take()的实现,可以先去复习一下,了解为什么LinkedBlockingQueue要如此设计。以下是更细致的讲解。
阻塞的入队操作PUT()
在队尾入队。putLock和notFull配合完成同步。
public void put(E e) throws InterruptedException {
if (e == null) throw new NullPointerException();
int c = -1;
Node&E& node = new Node&E&(e);
final ReentrantLock putLock = this.putL
final AtomicInteger count = this.
putLock.lockInterruptibly();
while (count.get() == capacity) {
notFull.await();
enqueue(node);
c = count.getAndIncrement();
if (c + 1 & capacity)
notFull.signal();
} finally {
putLock.unlock();
if (c == 0)
signalNotEmpty();
现在触发一个入队操作,分情况讨论。
case1:入队前,队列非空非满(长度大于等于2)
入队前需得到锁putLock。检查队列非满,无需等待条件notFull,直接入队。入队后,检查队列非满(精确说是入队前“将满”,但不影响理解),随机通知一个生产者条件notFull满足。最后,检查入队前队列非空,则无需通知条件notEmpty。
入队前队列非空非满(长度大于等于2),则head和tail指向的节点不同,入队与出队操作不会同时更新同一节点也就不存在竞争。因此,分别用两个锁同步入队、出队操作才能是线程安全的。进一步的,由于入队已经由锁putLock保护,则enqueue内部实现不需要加锁。
条件notFull可以只随机通知一个等待该条件的生产者线程(即,使用signal()而不是signalAll()。这顺便会减少无效竞争,提升性能)。这不会产生Object#notify()那样的缺陷,因为只有生产者在等待该条件,而且除非队列满,否则每次生产者入队后都会通知条件notFull,同时每次消费者出队后,如果队列不满,也会通知条件notFull满足(见take()方法)。
条件通知方法singal()是近乎“幂等”的:如果有线程在等待该条件,则随机选择一个线程通知;如果没有线程等待,则什么都不做,不会造成什么恶劣影响。
case2:入队前,队列满
入队前需得到锁putLock。检查队列满,则等待条件notFull。条件notFull可能由出队成功触发(必要的),也可能由入队成功触发(也是必要的,避免“丢失信号”的问题)。条件notFull满足后,入队。入队后,假设检查队列满(队列非满的情况同case1),则无需通知条件notFull。最后,检查入队前队列非空,则无需通知条件notEmpty。
“丢失信号”问题:基于锁和条件队列的机制,在等待条件时会释放锁,这会产生一些令人迷惑的问题,增加了基于条件队列设计并发程序的难度。假设队列满时,存在3个生产者P1-P3(多于一个就可以)同时阻塞在10行;如果此时5个消费者C1-C5(多于一个就可以)快速、连续的出队并通知条件notFull满足,速度快到阻塞的3个生产者都被唤醒,但还没来得及开始竞争锁putLock,则相当于只发出了一个信号,其他信号“丢失”了——因为只有最后竞争到锁的那一个生产者P1收到的信号发挥了作用,其他生产者P2-P3会再次进入阻塞状态,看起来好像没有被唤醒过。然而,C1-C5出队了5个元素,后续只有P1入队1个元素,显然此时队列非满。因此,14-15行“入队完成时的通知”是必要的,保证了只要队列非满,每次入队后都能唤醒1个阻塞的生产者,来等待锁释放后竞争锁。即,P1完成入队后,如果检查到队列非满,会随机唤醒一个生产者P2,让P2在P1释放锁putLock后竞争锁,继续入队,P3同理。
case3:入队前,队列空
入队前需得到锁putLock。检查队列空,则无需等待条件notFull,直接入队。入队后,如果队列非满,则同case1;如果队列满,则同case2。最后,假设检查入队前队列空(队列非空的情况同case1),则随机通知一个消费者条件notEmpty满足。
只有入队前队列空的情况下,才需要通知条件notEmpty满足。因为如果队列非空,则出队操作不会阻塞在条件notEmpty上。另一方面,虽然已经有生产者完成了入队,但可能有消费者在生产者释放锁putLock后、通知条件notEmpty满足前,使队列变空;不过这没有影响,take()方法的while循环能够在线程竞争到锁之后再次确认。
通过入队和出队前检查队列长度(while+await),隐含保证了队列空时只允许入队操作,不存在竞争队列。
case4:入队前,队列长度为1
case4是一个特殊情况,分析方法类似于case1,但可能入队与出队之间存在竞争,我们稍后分析。
阻塞的出队操作TAKE()
在队头入队。takeLock和notEmpty配合完成同步。
public E take() throws InterruptedException {
int c = -1;
final AtomicInteger count = this.
final ReentrantLock takeLock = this.takeL
takeLock.lockInterruptibly();
while (count.get() == 0) {
notEmpty.await();
x = dequeue();
c = count.getAndDecrement();
if (c & 1)
notEmpty.signal();
} finally {
takeLock.unlock();
if (c == capacity)
signalNotFull();
依旧是四种case,put()和take()是对偶的,很容易分析,不赘述。
“CASE4 队列长度为1”时的特殊情况
队列长度为1时,到底入队和出队之间存在竞争吗?这取决于LinkedBlockingQueue的底层数据结构。
最简单的是使用朴素链表,可以自己实现,也可以使用JDK提供的非线程安全集合类,如LinkedList等。但是,队列长度为1时,朴素链表中的head、tail指向同一个节点,从而入队、出队更新同一个节点时存在竞争。
朴素链表:一个节点保存一个元素,不加任何控制和trick。典型如LinkedList。
增加dummy node可解决该问题(或者叫哨兵节点什么的)。定义Node(item, next),描述如下:
初始化链表时,创建dummy node:
dummy = new Node(null, null)
head = dummy.next // head 为 null &=& 队列空
tail = dummy // tail.item 为 null &=& 队列空
在队尾入队时,tail后移:
tail.next = new Node(newItem, null)
tail = tail.next
在队头出队时,dummy后移,同步更新head:
oldItem = head.item
dummy = dummy.next
dummy.item = null
head = dummy.next
return oldItem
在新的数据结构中,更新操作发生在dummy和tail上,head仅仅作为示意存在,跟随dummy节点更新。队列长度为1时,虽然head、tail仍指向同一个节点,但dummy、tail指向不同的节点,从而更新dummy和tail时不存在竞争。
源码中的head即为dummy,first即为head:
public LinkedBlockingQueue(int capacity) {
if (capacity &= 0) throw new IllegalArgumentException();
this.capacity =
last = head = new Node&E&(null);
private void enqueue(Node&E& node) {
// assert putLock.isHeldByCurrentThread();
// assert last.next ==
last = last.next =
private E dequeue() {
// assert takeLock.isHeldByCurrentThread();
// assert head.item ==
Node&E& h =
Node&E& first = h.
h.next = // help GC
E x = first.
first.item =
ENQUEUE和COUNT自增的先后顺序
以put()为例,count自增一定要晚于enqueue执行,否则take()方法的while循环检查会失效。
用一个最简单的场景来分析,只有一个生产者线程T1,一个消费者线程T2。
如果先count自增再enqueue
假设目前队列长度0,则事件发生顺序:
T1线程:count 自增
T2线程:while 检查 count & 0,无需等待条件 notEmpty
T2线程:dequeue 执行
T1线程:enqueue 执行
很明显,在事件1发生后事件4发生前,虽然count&0,但队列中实际是没有元素的。因此,事件3 dequeue会执行失败(预计抛出NullPointerException)。事件4也就不会发生了。
如果先enqueue再count自增
如果先enqueue再count自增,就不会存在该问题。
仍假设目前队列长度0,则事件发生顺序:
T1线程:enqueue 执行
T2线程:while 检查 count == 0,等待条件 notEmpty
T1线程:count 自增
T1线程:通知条件notFull满足
T1线程:通知条件notEmpty满足
T2线程:收到条件notEmpty
T2线程:while 检查 count & 0,无需等待条件 notEmpty
T2线程:dequeue 执行
换个方法,用状态机来描述:
事件E1发生前,队列处于状态S1
事件E1发生,线程T1 增加了一个队列元素,导致队列元素的数量大于count(1&0),队列转换到状态S2
事件E1发生后、直到事件E3发生前,队列一直处于状态S2
事件E3发生,线程T1 使count自增,导致队列元素的数量等于count(1=1),队列转换到状态S1
事件E3发生后、事件E8发生前,队列一直处于状态S1
很多读者可能第一次从状态机的角度来理解并发程序设计,所以猴子选择先写出状态迁移序列,如果能理解上述序列,我们再进行进一步的抽象。实际的状态机定义比下面要严谨的多,不过这里的描述已经足够了。
现在补充定义如下,不考虑入队和出队的区别:
队列元素的数量等于count的状态定义为状态S1
队列元素的数量大于count的状态定义为状态S2
enqueue操作定义为状态转换S1-&S2
count自增操作定义为状态转换S2-&S1
LinkedBlockingQueue中的同步机制保证了不会有其他线程看到状态S2,即,S1-&S2-&S1两个状态转换只能由线程T1连续完成,其他线程无法在中间插入状态转换。
在猴子的理解中,并发程序设计的本质是状态机,即维护合法的状态和状态转换。以上是一个极其简单的场景,用状态机举例子就可以描述;然而,复杂场景需要用状态机做数学证明,这使得用状态机描述并发程序设计不太受欢迎(虽然口头描述也不能算严格证明)。不过,理解实现中的各种代码顺序、猛不丁蹦出的trick,这些只是“知其所以然”;通过简单的例子来掌握其状态机本质,才能让我们了解其如何保证线程安全性,自己也能写出类似的实现,做到“知其然而知其所以然”。后面会继续用状态机分析ConcurrentLinkedQueue的源码,敬请期待。
非阻塞方法offer()和poll()
分析了两个阻塞方法put()、take()后,非阻塞方法就简单了。
以offer为例,poll()同理。假设此时队列非空。
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
final AtomicInteger count = this.
if (count.get() == capacity)
int c = -1;
Node&E& node = new Node&E&(e);
final ReentrantLock putLock = this.putL
putLock.lock();
if (count.get() & capacity) {
enqueue(node);
c = count.getAndIncrement();
if (c + 1 & capacity)
notFull.signal();
} finally {
putLock.unlock();
if (c == 0)
signalNotEmpty();
return c &= 0;
case1:入队前,队列非满
入队前需得到锁putLock。检查队列非满(隐含表明“无需等待条件notFull”),直接入队。入队后,检查队列非满,随机通知一个生产者(包括使用put()方法的生产者,下同)条件notFull满足。最后,检查入队前队列非空,则无需通知条件notEmpty。
可以看到,瞬时版offer()在队列非满时的行为与put()相同。
case2:入队前,队列满
入队前需得到锁putLock。检查队列满,直接退出try-block。后同case1。
队列满时,offer()与put()的区别就显现出来了。put()通过while循环阻塞,一直等到条件notFull得到满足;而offer()却直接返回。
一个小point:
c在申请锁putLock前被赋值为-1。接下来,如果入队成功,会执行c = count.getAndIncrement();一句,则释放锁后,c的值将大于等于0。于是,这里直接用c是否大于等于0来判断是否入队成功。这种实现牺牲了可读性,只换来了无足轻重的性能或代码量的优化。自己在开发时,不要编写这种代码。
同上,以offer()为例。假设此时队列非空。
public boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedException {
if (e == null) throw new NullPointerException();
long nanos = unit.toNanos(timeout);
int c = -1;
final ReentrantLock putLock = this.putL
final AtomicInteger count = this.
putLock.lockInterruptibly();
while (count.get() == capacity) {
if (nanos &= 0)
nanos = notFull.awaitNanos(nanos);
enqueue(new Node&E&(e));
c = count.getAndIncrement();
if (c + 1 & capacity)
notFull.signal();
} finally {
putLock.unlock();
if (c == 0)
signalNotEmpty();
该方法同put()很像,12-13行判断nanos超时的情况(吞掉了timeout参数非法的异常情况),所以区别只有14行:将阻塞的notFull.await()换成非阻塞的超时版notFull.awaitNanos(nanos)。
awaitNanos()的实现有点意思,这里不表。其实现类中的Javadoc描述非常干练:“Block until signalled, interrupted, or timed out.”,返回值为剩余时间。剩余时间小于等于参数nanos,表示:
条件notFull满足(剩余时间大于0)
等待的总时长已超过timeout(剩余时间小于等于0)
nanos首先被初始化为timeout;接下来,消费者线程可能阻塞、收到信号多次,每次收到信号被唤醒,返回的剩余时间都大于0并小于等于参数nanos,再用剩余时间作为下次等待的参数nanos,直到剩余时间小于等于0。以此实现总时长不超过timeout的超时检测。
其他同put()方法。
12-13行判断nanos参数非法后,直接返回了false。实现有问题,有可能违反接口声明。
根据Javadoc的返回值声明,返回值true表示入队成功,false表示入队失败。但如果传进来的timeout是一个负数,那么5行初始化的nanos也将是一个负数;进而一进入while循环,就在13行返回了false。然而,这是一种参数非法的情况,返回false让人误以为参数正常,只是入队失败。这违反了接口声明,并且非常难以发现。
应该在函数头部就将参数非法的情况检查出来,相应抛出IllegalArgumentException。
LinkedBlockingQueue与ArrayBlockingQueue的区别
github上LinkedBlockingQueue和ArrayBlockingQueue的使用频率都很高。大部分情况下都可以也建议使用LinkedBlockingQueue,但清楚二者的异同点,方能对症下药,在针对不同的优化场景选择最合适的方案。
LinkedBlockingQueue底层用链表实现:ArrayBlockingQueue底层用数组实现
LinkedBlockingQueue支持不指定容量的无界队列(长度最大值Integer.MAX_VALUE);ArrayBlockingQueue必须指定容量,无法扩容
LinkedBlockingQueue支持懒加载:ArrayBlockingQueue不支持
ArrayBlockingQueue入队时不生成额外对象:LinkedBlockingQueue需生成Node对象,消耗时间,且GC压力大
LinkedBlockingQueue的入队和出队分别用两把锁保护,无竞争,二者不会互相影响;ArrayBlockingQueue的入队和出队共用一把锁,入队和出队存在竞争,一方速度高时另一方速度会变低。不考虑分配对象、GC等因素的话,ArrayBlockingQueue并发性能要低于LinkedBlockingQueue
可以看到,LinkedBlockingQueue整体上是优于ArrayBlockingQueue的。所以,除非某些特殊原因,否则应优先使用LinkedBlockingQueue。
可能不全,欢迎评论,随时增改。
可能感兴趣的文章
hashtable是不是要写对了啊?
关于ImportNew
ImportNew 专注于 Java 技术分享。于日 11:11正式上线。是的,这是一个很特别的时刻 :)
ImportNew 由两个 Java 关键字 import 和 new 组成,意指:Java 开发者学习新知识的网站。 import 可认为是学习和吸收, new 则可认为是新知识、新技术圈子和新朋友……
新浪微博:
推荐微信号
反馈建议:ImportNew.
广告与商务合作QQ:
– 好的话题、有启发的回复、值得信赖的圈子
– 写了文章?看干货?去头条!
– 为IT单身男女服务的征婚传播平台
– 优秀的工具资源导航
– 活跃 & 专业的翻译小组
– 国内外的精选博客文章
– UI,网页,交互和用户体验
– JavaScript, HTML5, CSS
– 专注Android技术分享
– 专注iOS技术分享
– 专注Java技术分享
– 专注Python技术分享
& 2018 ImportNew他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)博客分类:
Queue接口定义:
AbstractQueue简介:
ConcurrentLinkedQueue解析:
/*
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
package java.util.
import java.util.C
import java.util.Q
* A {@link java.util.Queue} that additionally supports operations
* that wait for the queue to become non-empty when retrieving an
* element, and wait for space to become available in the queue when
* storing an element.
BlockingQueue是一个支持消费队列元素,如果为空,则等待,生产元素到队列
,如果队列满,则等待操作的队列。
* &p&&tt&BlockingQueue&/tt& methods come in four forms, with different ways
* of handling operations that cannot be satisfied immediately, but may be
* satisfied at some point in the future:
* one throws an exception, the second returns a special value (either
* &tt&null&/tt& or &tt&false&/tt&, depending on the operation), the third
* blocks the current thread indefinitely until the operation can succeed,
* and the fourth blocks for only a given maximum time limit before giving
These methods are summarized in the following table:
BlockingQueue有四种形式的操作,不同方式操作,当在处理过程中,操作不能满足,
也许会在将来的某个时刻满足:
一种抛出异常,第二种返回null或false,依赖于具体的操作,第三种非确定性阻塞当前线程,
直到操作成功,第四种,在取消操作之前,超时阻塞等待条件。四种形式总结如下:
一下是四种处理方法对应的方法
* &table BORDER CELLPADDING=3 CELLSPACING=1&
&td ALIGN=CENTER&[i]Throws exception[/i]&/td&
&td ALIGN=CENTER&[i]Special value[/i]&/td&
&td ALIGN=CENTER&[i]Blocks[/i]&/td&
&td ALIGN=CENTER&[i]Times out[/i]&/td&
&td&&b&Insert&/b&&/td&
&td&{@link #add add(e)}&/td&
&td&{@link #offer offer(e)}&/td&
&td&{@link #put put(e)}&/td&阻塞
&td&{@link #offer(Object, long, TimeUnit) offer(e, time, unit)}&/td&超时阻塞
&td&&b&Remove&/b&&/td&
&td&{@link #remove remove()}&/td&
&td&{@link #poll poll()}&/td&
&td&{@link #take take()}&/td&阻塞
&td&{@link #poll(long, TimeUnit) poll(time, unit)}&/td&超时阻塞
&td&&b&Examine&/b&&/td&
&td&{@link #element element()}&/td&
&td&{@link #peek peek()}&/td&
&td&[i]not applicable[/i]&/td&
&td&[i]not applicable[/i]&/td&
* &/table&
* &p&A &tt&BlockingQueue&/tt& does not accept &tt&null&/tt& elements.
* Implementations throw &tt&NullPointerException&/tt& on attempts
* to &tt&add&/tt&, &tt&put&/tt& or &tt&offer&/tt& a &tt&null&/tt&.
* &tt&null&/tt& is used as a sentinel value to indicate failure of
* &tt&poll&/tt& operations.
BlockingQueue不允许null值元素,当add,put,offer为null时,则抛出空指针异常。
null最为poll失败的标识。
* &p&A &tt&BlockingQueue&/tt& may be capacity bounded. At any given
* time it may have a &tt&remainingCapacity&/tt& beyond which no
* additional elements can be &tt&put&/tt& without blocking.
* A &tt&BlockingQueue&/tt& without any intrinsic capacity constraints always
* reports a remaining capacity of &tt&Integer.MAX_VALUE&/tt&.
BlockingQueue也许是有界的。在任何时候,当要生产的元素大于队列的剩余空间,则阻塞。
BlockingQueue没有严格容量限制,总是报告Integer.MAX_VALUE的剩余容量。
* &p& &tt&BlockingQueue&/tt& implementations are designed to be used
* primarily for producer-consumer queues, but additionally support
* the {@link java.util.Collection} interface.
So, for example, it is
* possible to remove an arbitrary element from a queue using
* &tt&remove(x)&/tt&. However, such operations are in general
* [i]not[/i] performed very efficiently, and are intended for only
* occasional use, such as when a queued message is cancelled.
BlockingQueue被设计用于生产消费者队列场景,同时支持Collection接口的相关操作。
BlockingQueue可能会用remove从队列移除一个元素。然而,这种操作在大部分情况下
,不会被执行,也许偶尔会用,不如当队列消息取消。
* &p& &tt&BlockingQueue&/tt& implementations are thread-safe.
* queuing methods achieve their effects atomically using internal
* locks or other forms of concurrency control. However, the
* [i]bulk[/i] Collection operations &tt&addAll&/tt&,
* &tt&containsAll&/tt&, &tt&retainAll&/tt& and &tt&removeAll&/tt& are
* [i]not[/i] necessarily performed atomically unless specified
* otherwise in an implementation. So it is possible, for example, for
* &tt&addAll(c)&/tt& to fail (throwing an exception) after adding
* only some of the elements in &tt&c&/tt&.
BlockingQueue是线程安全的。队列的所有方法都是用内部锁或其他形式的同步控制,
实现高效的原子性操作。然而集合批量操作addAll,containsAll,retainAll,removeAll
是不需要原子性的操作,除非在特殊队列实现中。但是有一个可能,当批量插入时,
如果其中一个插入失败,则抛出异常。
* &p&A &tt&BlockingQueue&/tt& does [i]not[/i] intrinsically support
* any kind of "close" or "shutdown" operation to
* indicate that no more items will be added.
The needs and usage of
* such features tend to be implementation-dependent. For example, a
* common tactic is for producers to insert special
* [i]end-of-stream[/i] or [i]poison[/i] objects, that are
* interpreted accordingly when taken by consumers.
BlockingQueue本质上是不支持close和shutdown等操作表示,不允许生产元素。
这种需要我们可以用一种跟着特点单独实现。
* Usage example, based on a typical producer-consumer scenario.
* Note that a &tt&BlockingQueue&/tt& can safely be used with multiple
* producers and multiple consumers.
典型的生产消费者模式,BlockingQueue可在多个生产者和消费者情况下,线程安全使用。
* class Producer implements Runnable {
private final BlockingQ
Producer(BlockingQueue q) { queue = }
public void run() {
while (true) { queue.put(produce()); }
} catch (InterruptedException ex) { ... handle ...}
Object produce() { ... }
* class Consumer implements Runnable {
private final BlockingQ
Consumer(BlockingQueue q) { queue = }
public void run() {
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();
* &p&Memory consistency effects: As with other concurrent
* collections, actions in a thread prior to placing an object into a
* {@code BlockingQueue}
* [url=package-summary.html#MemoryVisibility]&i&happen-before&/i&[/url]
* actions subsequent to the access or removal of that element from
* the {@code BlockingQueue} in another thread.
内存一致性,像其他并发集合一样,生产消息发生在另一个消费者消费消息之前。
* &p&This interface is a member of the
* &a href="{@docRoot}/../technotes/guides/collections/index.html"&
* Java Collections Framework&/a&.
* @since 1.5
* @author Doug Lea
* @param &E& the type of elements held in this collection
public interface BlockingQueue&E& extends Queue&E& {
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions, returning
* &tt&true&/tt& upon success and throwing an
* &tt&IllegalStateException&/tt& if no space is currently available.
* When using a capacity-restricted queue, it is generally preferable to
* use {@link #offer(Object) offer}.
如果在队列容量没满的情况下,添加元素,立即成功,并返回true,如果队列
没有空间可利用,则抛出异常,一般情况下,最好用offer方法。
* @param e the element to add
* @return &tt&true&/tt& (as specified by {@link Collection#add})
* @throws IllegalStateException if the element cannot be added at this
time due to capacity restrictions
* @throws ClassCastException if the class of the specified element
prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
element prevents it from being added to this queue
boolean add(E e);
* Inserts the specified element into this queue if it is possible to do
* so immediately without violating capacity restrictions, returning
* &tt&true&/tt& upon success and &tt&false&/tt& if no space is currently
* available.
When using a capacity-restricted queue, this method is
* generally preferable to {@link #add}, which can fail to insert an
* element only by throwing an exception.
如果在队列容量没满的情况下,添加元素,立即成功,并返回true,如果队列
没有空间可利用,则返回false。在队列有界的情况下,一般用add方法,失败则
仅仅抛出异常。
* @param e the element to add
* @return &tt&true&/tt& if the element was added to this queue, else
&tt&false&/tt&
* @throws ClassCastException if the class of the specified element
prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
element prevents it from being added to this queue
boolean offer(E e);
* Inserts the specified element into this queue, waiting if necessary
* for space to become available.
插入元素到队列中,如果无空间可利用,则等待队列空间可用条件
* @param e the element to add
* @throws InterruptedException if interrupted while waiting
* @throws ClassCastException if the class of the specified element
prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
element prevents it from being added to this queue
void put(E e) throws InterruptedE
* Inserts the specified element into this queue, waiting up to the
* specified wait time if necessary for space to become available.
插入元素到队列中,如果无空间可利用,则超时等待队列空间可用条件
* @param e the element to add
* @param timeout how long to wait before giving up, in units of
&tt&unit&/tt&
* @param unit a &tt&TimeUnit&/tt& determining how to interpret the
&tt&timeout&/tt& parameter
* @return &tt&true&/tt& if successful, or &tt&false&/tt& if
the specified waiting time elapses before space is available
* @throws InterruptedException if interrupted while waiting
* @throws ClassCastException if the class of the specified element
prevents it from being added to this queue
* @throws NullPointerException if the specified element is null
* @throws IllegalArgumentException if some property of the specified
element prevents it from being added to this queue
boolean offer(E e, long timeout, TimeUnit unit)
throws InterruptedE
* Retrieves and removes the head of this queue, waiting if necessary
* until an element becomes available.
从队列头部消费一个元素,如果队列为空,则等待队列不为空条件
* @return the head of this queue
* @throws InterruptedException if interrupted while waiting
E take() throws InterruptedE
* Retrieves and removes the head of this queue, waiting up to the
* specified wait time if necessary for an element to become available.
从队列头部消费一个元素,如果队列为空,则超时等待队列不为空条件
* @param timeout how long to wait before giving up, in units of
&tt&unit&/tt&
* @param unit a &tt&TimeUnit&/tt& determining how to interpret the
&tt&timeout&/tt& parameter
* @return the head of this queue, or &tt&null&/tt& if the
specified waiting time elapses before an element is available
* @throws InterruptedException if interrupted while waiting
E poll(long timeout, TimeUnit unit)
throws InterruptedE
* Returns the number of additional elements that this queue can ideally
* (in the absence of memory or resource constraints) accept without
* blocking, or &tt&Integer.MAX_VALUE&/tt& if there is no intrinsic
在没有阻塞的情况下,队列可以添加的元素,即剩余容量
* &p&Note that you [i]cannot[/i] always tell if an attempt to insert
* an element will succeed by inspecting &tt&remainingCapacity&/tt&
* because it may be the case that another thread is about to
* insert or remove an element.
* @return the remaining capacity
int remainingCapacity();
* Removes a single instance of the specified element from this queue,
* if it is present.
More formally, removes an element &tt&e&/tt& such
* that &tt&o.equals(e)&/tt&, if this queue contains one or more such
* elements.
从队列中移除一个元素
* Returns &tt&true&/tt& if this queue contained the specified element
* (or equivalently, if this queue changed as a result of the call).
* @param o element to be removed from this queue, if present
* @return &tt&true&/tt& if this queue changed as a result of the call
* @throws ClassCastException if the class of the specified element
is incompatible with this queue
([url=../Collection.html#optional-restrictions]optional[/url])
* @throws NullPointerException if the specified element is null
([url=../Collection.html#optional-restrictions]optional[/url])
boolean remove(Object o);
* Returns &tt&true&/tt& if this queue contains the specified element.
* More formally, returns &tt&true&/tt& if and only if this queue contains
* at least one element &tt&e&/tt& such that &tt&o.equals(e)&/tt&.
判断队列中是否包含元素,队列中至少有一个元素与之相等,则返回true
* @param o object to be checked for containment in this queue
* @return &tt&true&/tt& if this queue contains the specified element
* @throws ClassCastException if the class of the specified element
is incompatible with this queue
([url=../Collection.html#optional-restrictions]optional[/url])
* @throws NullPointerException if the specified element is null
([url=../Collection.html#optional-restrictions]optional[/url])
public boolean contains(Object o);
* Removes all available elements from this queue and adds them
* to the given collection.
This operation may be more
* efficient than repeatedly polling this queue.
* encountered while attempting to add elements to
* collection &tt&c&/tt& may result in elements being in neither,
* either or both collections when the associated exception is
Attempts to drain a queue to itself result in
* &tt&IllegalArgumentException&/tt&. Further, the behavior of
* this operation is undefined if the specified collection is
* modified while the operation is in progress.
移除队列中所有的元素,并添加到给定的集合中。则个操作也许比重入的
poll更有效。当在将元素添加到集合中时,如果有失败,则抛出关联的异常。
尝试将队列drain到自己,则将抛出非法参数异常。进一步说,在操作集合的过程中,
集合被修改,则drain的结果将是不确定的。
* @param c the collection to transfer elements into
* @return the number of elements transferred
* @throws UnsupportedOperationException if addition of elements
is not supported by the specified collection
* @throws ClassCastException if the class of an element of this queue
prevents it from being added to the specified collection
* @throws NullPointerException if the specified collection is null
* @throws IllegalArgumentException if the specified collection is this
queue, or some property of an element of this queue prevents
it from being added to the specified collection
int drainTo(Collection&? super E& c);
* Removes at most the given number of available elements from
* this queue and adds them to the given collection.
* encountered while attempting to add elements to
* collection &tt&c&/tt& may result in elements being in neither,
* either or both collections when the associated exception is
Attempts to drain a queue to itself result in
* &tt&IllegalArgumentException&/tt&. Further, the behavior of
* this operation is undefined if the specified collection is
* modified while the operation is in progress.
移除队列中最多maxElements的元素,并添加到给定的集合中。
* @param c the collection to transfer elements into
* @param maxElements the maximum number of elements to transfer
* @return the number of elements transferred
* @throws UnsupportedOperationException if addition of elements
is not supported by the specified collection
* @throws ClassCastException if the class of an element of this queue
prevents it from being added to the specified collection
* @throws NullPointerException if the specified collection is null
* @throws IllegalArgumentException if the specified collection is this
queue, or some property of an element of this queue prevents
it from being added to the specified collection
int drainTo(Collection&? super E& c, int maxElements);
Donald_Draper
浏览: 231273 次
ron.luo 写道写的特别好,能分享下源码地址?https: ...
写的特别好,能分享下源码地址?
taibangtle~~~
xuexile ~~~~
学习了~~~·
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'}

我要回帖

更多关于 aio和nio的区别和场景 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信