阻塞队列BlockingQueue
支持两个附加操作的 Queue
,这两个操作是:获取元素时等待队列变为非空,以及存储元素时等待空间变得可用。
BlockingQueue
方法以四种形式出现,对于不能立即满足但可能在将来某一时刻可以满足的操作,这四种形式的处理方式不同:第一种是抛出一个异常,第二种是返回一个特殊值(null
或
false,具体取决于操作),第三种是在操作可以成功前,无限期地阻塞当前线程,第四种是在放弃前只在给定的最大时间限制内阻塞。下表中总结了这些方法:
BlockingQueue 不接受 null 元素。试图 add、put 或
offer 一个 null 元素时,某些实现会抛NullPointerException。
null 被用作指示 poll 操作失败的警戒值。
BlockingQueue 可以是限定容量的。它在任意给定时间都可以有一个
remainingCapacity,超出此容量,便无法无阻塞地 put 附加元素。没有任何内部容量约束的
BlockingQueue 总是报告 Integer.MAX_VALUE 的剩余容量。
BlockingQueue 实现主要用于生产者-使用者队列,但它另外还支持 Collection
接口。因此,举例来说,使用 remove(x) 从队列中移除任意一个元素是有可能的。然而,这种操作通常不
会有效执行,只能有计划地偶尔使用,比如在取消排队信息时。BlockingQueue
实现是线程安全的。所有排队方法都可以使用内部锁或其他形式的并发控制来自动达到它们的目的。然而,大量的 Collection
操作(addAll、containsAll、retainAll 和
removeAll)没有 必要自动执行,除非在实现中特别说明。因此,举例来说,在只添加了 c
中的一些元素后,addAll(c) 有可能失败(抛出一个异常)。
BlockingQueue 实质上不
支持使用任何一种“close”或“shutdown”操作来指示不再添加任何项。这种功能的需求和使用有依赖于实现的倾向。例如,一种常用的策略是:对于生产者,插入特殊的
end-of-stream 或 poison 对象,并根据使用者获取这些对象的时间来对它们进行解释。
以下是基于典型的生产者-使用者场景的一个用例。注意,BlockingQueue 可以安全地与多个生产者和多个使用者一起使用。
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();
}
}
内存一致性效果:当存在其他并发 collection 时,将对象放入 BlockingQueue
之前的线程中的操作 happen-before 随后通过另一线程从
BlockingQueue
中访问或移除该元素的操作。
public class ArrayBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
一个由数组支持的有界阻塞队列。此队列按
FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部
是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为
true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”。
public class LinkedBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
一个基于已链接节点的、范围任意的 blocking queue。此队列按
FIFO(先进先出)排序元素。队列的头部 是在队列中时间最长的元素。队列的尾部
是在队列中时间最短的元素。新元素插入到队列的尾部,并且队列获取操作会获得位于队列头部的元素。链接队列的吞吐量通常要高于基于数组的队列,但是在大多数并发应用程序中,其可预知的性能要低。
可选的容量范围构造方法参数作为防止队列过度扩展的一种方法。如果未指定容量,则它等于 Integer.MAX_VALUE
。除非插入节点会使队列超出容量,否则每次插入后会动态地创建链接节点。
public class DelayQueue<E extends Delayed>
extends AbstractQueue<E>
implements BlockingQueue<E>
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部
是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回
null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0
的值时,将发生到期。即使无法使用 take 或 poll
移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size 方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素。
public class PriorityBlockingQueue<E>
extends AbstractQueue<E>
implements BlockingQueue<E>, Serializable
一个无界阻塞队列,它使用与类 PriorityQueue
相同的顺序规则,并且提供了阻塞获取操作。虽然此队列逻辑上是无界的,但是资源被耗尽时试图执行 add 操作也将失败(导致
OutOfMemoryError)。此类不允许使用 null 元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象(这样做会导致抛出
ClassCastException)。
此类及其迭代器可以实现 Collection
和 Iterator
接口的所有可选 方法。iterator()
方法中提供的迭代器并不 保证以特定的顺序遍历 PriorityBlockingQueue 的元素。如果需要有序地进行遍历,则应考虑使用
Arrays.sort(pq.toArray())。此外,可以使用方法 drainTo 按优先级顺序移除
全部或部分元素,并将它们放在另一个 collection 中。
在此类上进行的操作不保证具有同等优先级的元素的顺序。如果需要实施某一排序,那么可以定义自定义类或者比较器,比较器可使用修改键断开主优先级值之间的联系。例如,以下是应用先进先出
(first-in-first-out) 规则断开可比较元素之间联系的一个类。要使用该类,则需要插入一个新的
FIFOEntry(anEntry) 来替换普通的条目对象。
class FIFOEntry<E extends Comparable<? super E>>
implements Comparable<FIFOEntry<E>> {
final static AtomicLong seq = new AtomicLong();
final long seqNum;
final E entry;
public FIFOEntry(E entry) {
seqNum = seq.getAndIncrement();
this.entry = entry;
}
public E getEntry() { return entry; }
public int compareTo(FIFOEntry<E> other) {
int res = entry.compareTo(other.entry);
if (res == 0 && other.entry != this.entry)
res = (seqNum < other.seqNum ? -1 : 1);
return res;
}
}
分享到:
相关推荐
阻塞队列(BlockingQueue)是一种特殊的队列,它支持两个附加操作:阻塞的插入方法put和阻塞的移除方法take。BlockingQueue继承了Queue接口,是Java 5中加入的。 BlockingQueue常用方法示例: 1. add(E e):添加一...
### 10、阻塞队列BlockingQueue 实战及其原理分析 #### 一、阻塞队列概述 阻塞队列(BlockingQueue)是Java语言中`java.util.concurrent`包下提供的一种重要的线程安全队列。它继承自`Queue`接口,并在此基础上...
阻塞队列BlockingQueue是Java并发编程中一个重要的数据结构,它是线程安全的队列,主要用于生产者消费者模型中的数据交换。在Java的`java.util.concurrent`包中,提供了多种实现阻塞队列的类,如`ArrayBlockingQueue...
6.6 阻塞队列BlockingQueue 实战及其原 理分析一副本.mp4
6.7 阻塞队列BlockingQueue 实战及其原 理分析二副本.mp4
6.6 阻塞队列BlockingQueue 实战及其原 理分析一副本副本.mp4
6.7 阻塞队列BlockingQueue 实战及其原 理分析二副本副本.mp4
6.6 阻塞队列BlockingQueue 实战及其原 理分析一副本副本副本.mp4
Java中的阻塞队列BlockingQueue是一种并发编程中常用的工具,它实现了线程间的同步和通信。阻塞队列的核心特性在于当队列为空时,尝试获取元素的线程会被阻塞,直到其他线程添加元素;当队列满时,尝试添加元素的...
### BlockingQueue(阻塞队列)详解 #### 一、前言 随着现代软件系统对并发性能需求的不断提高,多线程编程技术逐渐成为开发人员不可或缺的技能之一。在Java平台中,`java.util.concurrent`包提供了丰富的工具来...
8. 阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 ...
8. 阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 ...
阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航 映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 ...
在Java编程中,`BlockingQueue`(阻塞队列)是一种重要的并发工具,它结合了队列的数据结构和线程同步机制。`BlockingQueue`接口位于`java.util.concurrent`包中,提供了线程安全的数据结构,可以用于实现生产者-...
在C++环境中,`BlockingQueue.h`可能是一个自定义实现的阻塞队列头文件。它可能会包含如下内容: 1. **模板类定义**:定义一个模板类`BlockingQueue<T>`,其中`T`代表队列中元素的类型。 2. **数据成员**:使用`std...
在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题。通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便利。本文简要介绍下BlockingQueue...
阻塞栈,即阻塞双端队列(BlockingDeque),在Java中由`LinkedBlockingDeque`实现。它同时具备队列和栈的特点,允许在两端进行插入和删除操作。与阻塞队列类似,当栈为空或满时,操作会阻塞,从而实现了线程间的同步...
8. 阻塞双端队列 BlockingDeque 9. 链阻塞双端队列 LinkedBlockingDeque 10. 并发 Map(映射) ConcurrentMap 11. 并发导航映射 ConcurrentNavigableMap 12. 闭锁 CountDownLatch 13. 栅栏 CyclicBarrier 14. 交换机 ...
Java中的阻塞队列实现主要依赖于`java.util.concurrent`包下的几个类,如`BlockingQueue`接口、`ArrayBlockingQueue`、`LinkedBlockingQueue`等。`BlockingQueue`接口定义了一组操作,如`put`、`take`、`offer`等,...
阻塞队列(BlockingQueue)是Java并发包(java.util.concurrent)中的一个重要数据结构,它实现了队列的特性,同时具备线程安全的特性。当队列满时,添加元素的线程会被阻塞,直到队列有空位;当队列为空时,取出...