BlockingQueue 阻塞队列(生产/消费者队列)
1:BlockingQueue的继承关系
java.util.concurrent 包里的 BlockingQueue是一个接口, 继承Queue接口,Queue接口继承 Collection
BlockingQueue----->Queue-->Collection
BlockingQueue即阻塞队列,它是基于ReentrantLock

2:核心方法
BlockingQueue 具有 4 组不同的方法用于插入、移除以及对队列中的元素进行检查。如果请求的操作不能得到立即执行的话,每个方法的表现也不同。这些方法如下:

四组不同的行为方式解释:
1(异常)
如果试图的操作无法立即执行,抛一个异常。
2(特定值)
如果试图的操作无法立即执行,返回一个特定的值(常常是 true / false)。
3 (阻塞)
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行。
4(超时)
如果试图的操作无法立即执行,该方法调用将会发生阻塞,直到能够执行,但等待时间不会超过给定值。返回一个特定值以告知该操作是否成功(典型的是 true / false)。
不能向BlockingQueue插入一个空对象,否则会抛出NullPointerException,相应的实现类校验代码
private static void checkNotNull(Object v) {
if (v == null)
throw new NullPointerException();
}
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 对象,并根据使用者获取这些对象的时间来对它们进行解释。
3:BlockingQueue的实现类
BlockingQueue 是个接口,你需要使用它的实现之一来使用BlockingQueue,Java.util.concurrent包下具有以下 BlockingQueue 接口的实现类:

3.1: 数组阻塞队列 ArrayBlockingQueue
一个由数组支持的有界阻塞队列。此队列按 FIFO(先进先出)原则对元素进行排序。队列的头部 是在队列中存在时间最长的元素。队列的尾部 是在队列中存在时间最短的元素。新元素插入到队列的尾部,队列获取操作则是从队列头部开始获得元素。
这是一个典型的“有界缓存区”,固定大小的数组在其中保持生产者插入的元素和使用者提取的元素。一旦创建了这样的缓存区,就不能再增加其容量。试图向已满队列中放入元素会导致操作受阻塞;试图从空队列中提取元素将导致类似阻塞。
此类支持对等待的生产者线程和使用者线程进行排序的可选公平策略。默认情况下,不保证是这种排序。然而,通过将公平性 (fairness) 设置为 true 而构造的队列允许按照 FIFO 顺序访问线程。公平性通常会降低吞吐量,但也减少了可变性和避免了“不平衡性”
3.2: 延迟队列 DelayQueue
Delayed 元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部 是延迟期满后保存时间最长的 Delayed 元素。如果延迟都还没有期满,则队列没有头部,并且 poll 将返回 null。当一个元素的 getDelay(TimeUnit.NANOSECONDS) 方法返回一个小于等于 0 的值时,将发生到期。即使无法使用 take 或 poll 移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size 方法同时返回到期和未到期元素的计数。此队列不允许使用 null 元素
3.3:链阻塞队列 LinkedBlockingQueue
LinkedBlockingQueue 类实现了 BlockingQueue 接口。
LinkedBlockingQueue 内部以一个链式结构(链接节点)对其元素进行存储。如果需要的话,这一链式结构可以选择一个上限。如果没有定义上限,将使用 Integer.MAX_VALUE 作为上限。
LinkedBlockingQueue 内部以 FIFO(先进先出)的顺序对元素进行存储。队列中的头元素在所有元素之中是放入时间最久的那个,而尾元素则是最短的那个。
3.4: 具有优先级的阻塞队列 PriorityBlockingQueue
PriorityBlockingQueue 类实现了 BlockingQueue 接口。
一个无界阻塞队列,它使用与类 PriorityQueue 相同的顺序规则,并且提供了阻塞获取操作。虽然此队列逻辑上是无界的,但是资源被耗尽时试图执行 add 操作也将失败(导致OutOfMemoryError)。此类不允许使用 null 元素。依赖自然顺序的优先级队列也不允许插入不可比较的对象(这样做会导致抛出 ClassCastException)。
此类及其迭代器可以实现 Collection 和 Iterator 接口的所有可选 方法。iterator() 方法中提供的迭代器并不 保证以特定的顺序遍历 PriorityBlockingQueue 的元素。如果需要有序地进行遍历,则应考虑使用 Arrays.sort(pq.toArray())。此外,可以使用方法 drainTo 按优先级顺序移除 全部或部分元素,并将它们放在另一个 collection 中。
在此类上进行的操作不保证具有同等优先级的元素的顺序。如果需要实施某一排序,那么可以定义自定义类或者比较器,比较器可使用修改键断开主优先级值之间的联系。例如,以下是应用先进先出 (first-in-first-out) 规则断开可比较元素之间联系的一个类。要使用该类,则需要插入一个新的 FIFOEntry(anEntry) 来替换普通的条目对象。
3.5: 同步队列 SynchronousQueue
SynchronousQueue 类实现了 BlockingQueue 接口。
SynchronousQueue 是一个特殊的队列,它的内部同时只能够容纳单个元素。如果该队列已有一元素的话,试图向队列中插入一个新元素的线程将会阻塞,直到另一个线程将该元素从队列中抽走。同样,如果该队列为空,试图向队列中抽取一个元素的线程将会阻塞,直到另一个线程向队列中插入了一条新的元素。
据此,把这个类称作一个队列显然是夸大其词了。它更多像是一个汇合点。
4、实例:
生产者消费者的示例代码
生产者:
public class Producer implements Runnable {
BlockingQueue<String> queue;
public Producer(BlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
String temp = "A Product, 生产线程:"
+ Thread.currentThread().getName();
System.out.println("I have made a product:"
+ Thread.currentThread().getName());
queue.put(temp);//如果队列是满的话,会阻塞当前线程
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消费者:
public class Consumer implements Runnable{
BlockingQueue<String> queue;
public Consumer(BlockingQueue<String> queue){
this.queue = queue;
}
@Override
public void run() {
try {
String temp = queue.take();//如果队列为空,会阻塞当前线程
System.out.println(temp);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试类:
public class Test3 {
public static void main(String[] args) {
BlockingQueue<String> queue = new LinkedBlockingQueue<String>(2);
// BlockingQueue<String> queue = new LinkedBlockingQueue<String>();
//不设置的话,LinkedBlockingQueue默认大小为Integer.MAX_VALUE
// BlockingQueue<String> queue = new ArrayBlockingQueue<String>(2);
Consumer consumer = new Consumer(queue);
Producer producer = new Producer(queue);
for (int i = 0; i < 5; i++) {
new Thread(producer, "Producer" + (i + 1)).start();
new Thread(consumer, "Consumer" + (i + 1)).start();
}
}
}
打印结果:
I have made a product:Producer1
I have made a product:Producer2
A Product, 生产线程:Producer1
A Product, 生产线程:Producer2
I have made a product:Producer3
A Product, 生产线程:Producer3
I have made a product:Producer5
I have made a product:Producer4
A Product, 生产线程:Producer5
A Product, 生产线程:Producer4
由于队列的大小限定成了2,所以最多只有两个产品被加入到队列当中,而且消费者取到产品的顺序也是按照生产的先后顺序,原因就是LinkedBlockingQueue和ArrayBlockingQueue都是按照FIFO的顺序存取元素的。
关于更加详细的BlockingQueue的分析请看这篇:解读 Java 并发队列 BlockingQueue
原文:https://blog.csdn.net/wuzhiwei549/article/details/79869699
BlockingQueue 阻塞队列(生产/消费者队列)的更多相关文章
- ZooKeeper实现生产-消费者队列
[欢迎关注公众号:程序猿讲故事 (codestory),及时接收最新文章] 生产-消费者队列,用于多节点的分布式数据结构,生产和消费数据.生产者创建一个数据对象,并放到队列中:消费者从队列中取出一个数 ...
- Monitor 实现阻塞队列 + 生产消费者实例
转载至 https://www.codeproject.com/Articles/28785/Thread-synchronization-Wait-and-Pulse-demystified /* ...
- 生产消费者队列(TaskCompletionSource)的应用
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Li ...
- BlockingQueue阻塞队列(解决多线程中数据安全问题 可用于抢票,秒杀)
案例:一个线程类中 private static BlockingQueue<Map<String, String>> dataQueue = new LinkedBlocki ...
- BlockingQueue 阻塞队列实现异步事件
转载请注明出处:https://www.cnblogs.com/wenjunwei/p/10411444.html 前言 本文通过一个简单的例子,来展现如何使用阻塞队列(BlockingQueue)来 ...
- 【BlockingQueue】BlockingQueue 阻塞队列实现
前言: 在新增的Concurrent包中,BlockingQueue很好的解决了多线程中,如何高效安全“传输”数据的问题.通过这些高效并且线程安全的队列类,为我们快速搭建高质量的多线程程序带来极大的便 ...
- java并发编程工具类JUC第一篇:BlockingQueue阻塞队列
Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一个可以存取元素,并且线程安全的队列.换句话说,当多线程同时从 JavaBlocking ...
- 不允许还有Java程序员不了解BlockingQueue阻塞队列的实现原理
我们平时开发中好像很少使用到BlockingQueue(阻塞队列),比如我们想要存储一组数据的时候会使用ArrayList,想要存储键值对数据会使用HashMap,在什么场景下需要用到Blocking ...
- Java并发之BlockingQueue 阻塞队列(ArrayBlockingQueue、LinkedBlockingQueue、DelayQueue、PriorityBlockingQueue、SynchronousQueue)
package com.thread.test.thread; import java.util.Random; import java.util.concurrent.*; /** * Create ...
随机推荐
- 046:ORM模型介绍
ORM模型介绍: 随着项目越来越大,采用写原生SQL的方式在代码中会出现大量的SQL语句,那么问题就出现了: 1.SQL语句重复利用率不高,越复杂的SQL语句条件越多,代码越长.会出现很多相近的SQL ...
- 【NOIP2016提高A组8.11】自然数
题目 分析 \(O(n)\)求出mex(1,i)(1<=i<=n): 虽然0<=ai<=10^9,但只有n个数,所以mex一定小于等于n for(long long j=1;j ...
- linux运维、架构之路-SSH远程管理服务
一.SSH服务功能介绍 1.远程登录管理 提供类似telnet远程联机服务器的服务,即上面提到的SSH服务 2.远程传输文件 是类似FTP服务的sftp-server,借助SSH协议来传输数据的,提供 ...
- HDU 4300 Clairewd's message ( 拓展KMP )
题意 : 给你一个包含26个小写字母的明文密文转换信息字符串str,第一个表示'a'对应的密文是str[0].'b'对应str[1]……以此类推.接下来一行给你一个另一个字符串,这个字符串由密文+明文 ...
- sh_05_超市买苹果
sh_05_超市买苹果 # 1. 定义苹果的单价 price = 8.5 # 2. 挑选苹果 weight = 7.5 # 3. 计算付款金额 money = weight * price # 4. ...
- 修改select的默认样式
在我们用select的时候,通常因为他的默认样式比较丑而用自己样式,那首先要去掉他的默认样式 去掉select的边框和点击时的蓝色边框 select{border: none;outline: non ...
- Spring Cloud Commons教程(二)Spring RestTemplate作为负载平衡器客户端
RestTemplate可以自动配置为使用功能区.要创建负载平衡RestTemplate创建RestTemplate @Bean并使用@LoadBalanced限定符. 警告 通过自动配置不再创建Re ...
- [CSP-S模拟测试]:序列(构造)
题目描述 给定$N,A,B$,构造一个长度为$N$的排列,使得:$\bullet$排列长度为$N$:$\bullet$最长上升子序列长度为$A$:$\bullet$最长下降子序列长度为$B$.我们有$ ...
- (转载)《利用Python进行数据分析·第2版》电子书
https://www.jianshu.com/p/04d180d90a3f https://www.jianshu.com/p/04d180d90a3f https://www.jianshu.co ...
- Window7系统安装Ubuntu16双系统
在电脑上插入ubuntu系统启动盘,之前做好的u盘启动盘,重启计算机,进入BIOS设置界面,设置系统启动为u盘启动,保存后退出.之后进入ubuntu系统安装界面. 在安装界面中选择系统语言,选择安装u ...