java并发编程工具类JUC第一篇:BlockingQueue阻塞队列
Java BlockingQueue接口java.util.concurrent.BlockingQueue表示一个可以存取元素,并且线程安全的队列。换句话说,当多线程同时从 JavaBlockingQueue中插入元素、获取元素的时候,不会导致任何并发问题(元素被插入多次、处理多次等问题)。
从java BlockingQueue可以引申出一个概念:阻塞队列,是指队列本身可以阻塞线程向队列里面插入元素,或者阻塞线程从队列里面获取元素。比如:当一个线程尝试去从一个空队列里面获取元素的时候,这个线程将被阻塞直到队列内元素数量不再为空。当然,线程是否会被阻塞取决于你调用什么方法从BlockingQueue获取元素,有的方法会阻塞线程,有的方法会抛出异常等等,下文我们会详细介绍。
一、BlockingQueue 接口实现类
本文不会去介绍如何自己实现BlockingQueue接口,JUC已经为我们做好了相关的一些接口实现类。
BlockingQueue是一个java接口,当我们需要使用阻塞队列的时候,可以使用它的实现类。java.util.concurrent包里面有如下的一些实现类实现了BlockingQueue接口。
- ArrayBlockingQueue
- DelayQueue
- LinkedBlockingQueue
- LinkedBlockingDeque
- LinkedTransferQueue
- PriorityBlockingQueue
- SynchronousQueue
在本文以及后续的文章中,会依次为大家介绍这些实现类的作用及使用场景,期待您的关注。
二、BlockingQueue 应用场景介绍
BlockingQueue通常被应用在一个线程生产对象放入队列,与此同时另一个线程消费队列内的对象的场景下。下面的这张图说明了使用场景:

生产者线程不断的生产新的对象,并将他们插入到BlockingQueue,直到队列中object的数量达到队列存储容量的上限。也就是说当队列中对象达到容量上限的时候,生产者线程将被阻塞,不能再向队列中插入新的对象。生产者线程将保持阻塞等待状态,直到消费者线程从队列中拿走Object,让队列有空余位置放入新的对象。
消费者线程不断的从BlockingQueue取出对象并将其进行处理。如果消费者线程尝试从一个空队列中获取一个对象,消费者线程将被阻塞处于等待状态,直到生产者向队列中放入一个新的对象。
所以BlockingQueue经常被用于生产消费的缓冲队列,如果你不想用分布式的或者中间件消息队列(redis、kafka)等(因为对于一个小功能会增加比较大的独立中间件运维成本),BlockingQueue可以能是一个备选的选项。
2.1.BlockingQueue 方法介绍
JavaBlockingQueue 提供了四组不同的方法用于向队列中插入、移除、检查队列中包含某一元素对象。每一组方法在被调用之后的响应行为上有所不同,如下:
| 抛出异常 | 返回特定值 | 阻塞后一直等待 | 阻塞后等待超时 | |
|---|---|---|---|---|
| 插入对象 | add(o) | offer(o) | put(o) | offer(o, timeout, timeunit) |
| 移除对象 | remove(o) | poll() | take() | poll(timeout, timeunit) |
| 检查对象存在 | element() | peek() |
上面的方法的四种行为分别的含义是
- 抛出异常: 如果调用方法后不能立即响应结果(空队列或满队列),则抛出异常。
- 返回特定值: 如果调用方法后不能立即响应结果(空队列或满队列),则返回特定的值(通常是true/false),true表示方法执行成功,否则表示方法执行失败。
- 阻塞后一直等待: 如果调用方法后不能立即响应结果(空队列或满队列),该方法将被阻塞一直处于等待状态。
- 阻塞后等待超时: 如果调用方法后不能立即响应结果(空队列或满队列),该方法将在一定时间范围内被阻塞等待,也就是在超时时间范围内阻塞。当超出超时时间之后,方法线程将不再阻塞,而是返回一个特定的值(通常是true/false),true表示方法执行成功,否则表示方法执行失败。
另外,BlockingQueue队列不允许向其内部插入null,如果你向队列中插入null,将会引发NullPointerException异常。
一般的队列都是从队首放入对象,从队尾获取对象,BlockingQueue不仅支持从队首队尾操作数据对象,还支持从队列中其他任何位置操作数据。比如:你已经向队列中放入一个对象并等待处理,但是出于某些特殊原因希望将这个对象从队列中删除掉。你可以调用remove(o)方法来删除队列中的一个特定的o对象。当然我们的程序不能经常性的这样做,因为队列这种数据结构经常从中间位置操作数据的效率是极低的,所以除非必要不建议这样做。
add(o)
BlockingQueueadd() 方法可以将o对象以参数的形式插入到队列里面,如果队列里面有剩余空间,将被立即插入;如果队列里面没有剩余空间,add()方法将跑出 IllegalStateException.
offer(o)
BlockingQueueoffer() 方法可以将o对象以参数的形式插入到队列里面,如果队列里面有剩余空间,将被立即插入;如果队列里面没有剩余空间,offer()方法将返回特定的值false.
offer(o, long millis, TimeUnit timeUnit)
BlockingQueueoffer() 方法有另外一个版本的实现,存在超时时间的设置参数。这个版本的offer()方法将o对象以参数的形式插入到队列里面,如果队列里面有剩余空间,将被立即插入;如果队列里面没有剩余空间,调用offer方法的线程在超时时间内将被阻塞处于等到状态,当阻塞时间大于超时时间之后,队列内如果仍然没有剩余空间放入新对象,offer()方法将返回false.
put(o)
BlockingQueueput() 方法可以将o对象以参数的形式插入到队列里面,如果队列里面有剩余空间,将被立即插入;如果队列里面没有剩余空间,调用put的方法的线程将被阻塞,直到BlockingQueue里面腾出新的空间可以放入对象为止。
take()
BlockingQueuetake() 方法取出并移除队列中的第一个元素(对象),如果BlockingQueue队列中不包含任何的元素,调用take()方法的线程将被阻塞,直到有新的元素对象插入到队列中为止。
poll()
BlockingQueuepoll() 方法取出并移除队列中的第一个元素(对象),如果BlockingQueue队列中不包含任何的元素,poll()方法将返回null.
poll(long timeMillis, TimeUnit timeUnit)
BlockingQueuepoll(long timeMillis, TimeUnit timeUnit)方法同样存在一个超时时间限制的版本,正常情况下该方法取出并移除队列中的第一个元素(对象)。如果BlockingQueue队列中不包含任何的元素,在超时时间范围内,如果仍然没有新的对象放入队列,这个版本的poll()方法将被阻塞处于等待状态;当阻塞时间大于超时时间之后,poll(long timeMillis, TimeUnit timeUnit)返回null
remove(Object o)
BlockingQueueremove(Object o) 方法可以从队列中删除一个以参数形式给定的元素对象,remove()方法使用o.equals(element)将传入参数o与队列中的对象进行一一比对,从而判定要删除的对象是否在队列中存在,如果存在就从队列中删除并返回true,否则返回false。
需要注意的是:如果队列中有多个与传入参数equals相等的对象,只删除其中一个,不会将队列中所有匹配的对象都删除。
peek()
BlockingQueuepeek() 方法将取出队列中的第一个元素对象,但是并不会将其从队列中删除。如果队列中目前没有任何的元素,也就是空队列,peek()方法将返回null.
element()
BlockingQueueelement()方法将取出队列中的第一个元素对象,但是并不会将其从队列中删除。如果队列中目前没有任何的元素,也就是空队列,element()方法将抛出 NoSuchElementException.
contains(Object o)
BlockingQueuecontains(Object o) 方法用来判断当前队列中是否存在某个对象,该对象与传入参数o相等(Objects.equals(o, element)被用来判定对象的相等性)。遍历队列中的所有元素,一旦在队列中发现匹配的元素对象,该方法将返回true;如果没有任何的元素匹配相等,该方法返回false。
drainTo(Collection dest)
drainTo(Collection dest)方法一次性的将队列中的所有元素取出到集合类Collection dest对象中保存。
drainTo(Collection dest, int maxElements)
drainTo(Collection dest)方法一次性的从队列中取出maxElements个元素到集合类Collection dest对象中保存。
size()
BlockingQueuesize() 方法返回队列中目前共有多少个元素
remainingCapacity()
BlockingQueueremainingCapacity() 方法将返回队列目前还剩多少个可用空间用于放入新的对象。剩余空间容量=队列的总容量-已经被占用的空间数量
欢迎关注我的博客,里面有很多精品合集
- 本文转载注明出处(必须带连接,不能只转文字):字母哥博客。
觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。
- 《手摸手教你学Spring Boot2.0》
- 《Spring Security-JWT-OAuth2一本通》
- 《实战前后端分离RBAC权限管理系统》
- 《实战SpringCloud微服务从青铜到王者》
- 《VUE深入浅出系列》
java并发编程工具类JUC第一篇:BlockingQueue阻塞队列的更多相关文章
- java并发编程工具类JUC第二篇:ArrayBlockingQueue
类ArrayBlockingQueue是BlockingQueue接口的实现类,它是有界的阻塞队列,内部使用数组存储队列元素.这里的"有界"是指存储容量存在上限,不能无限存储元素. ...
- java并发编程工具类JUC第八篇:ConcurrentHashMap
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
- java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...
- java并发编程工具类JUC第四篇:LinkedBlockingQueue链表队列
在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue. LinkedBlockingQueue 队列是Blo ...
- java并发编程工具类JUC第三篇:DelayQueue延时队列
DelayQueue 是BlockingQueue接口的实现类,它根据"延时时间"来确定队列内的元素的处理优先级(即根据队列元素的"延时时间"进行排序).另一层 ...
- Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo
Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...
- java并发编程工具类辅助类:CountDownLatch、CyclicBarrier和 Semaphore
在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下 ...
- 【Java并发编程实战】----- AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...
- 【Java并发编程实战】—– AQS(四):CLH同步队列
在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...
随机推荐
- 【秒懂音视频开发】18_详解YUV
本文的主角是多媒体领域非常重要的一个概念:YUV. 简介 YUV,是一种颜色编码方法,跟RGB是同一个级别的概念,广泛应用于多媒体领域中. 也就是说,图像中每1个像素的颜色信息,除了可以用RGB的方式 ...
- 分享几个网址二维码生成api
分享几个网址二维码生成api 传入网址参数,或许二维码图片,扫二维码能直接跳转网址 http://b.bshare.cn/barCode?site=weixin&url=https://www ...
- 【ShardingSphere】ShardingSphere学习(二)-核心概念-SQL
逻辑表 水平拆分的数据库(表)的相同逻辑和数据结构表的总称. 例:订单数据根据主键尾数拆分为10张表,分别是t_order_0到t_order_9,他们的逻辑表名为t_order. 真实表 在分片的数 ...
- UVA11248 网络扩容(枚举割边扩充)
题意: 给你一个有向图,问你从1到n的最大流是多少?如果流量大于等于C那么直接输出一个串,否则输出只扩充一条边的流量就可以达到1->n大于等于C的所有边,如果扩充不了就输出另一个串.S ...
- hdu4995 (不错的小模拟)
题意: 输入n,m,k ,给你n个点,他们在一个一维坐标上,每个点有两个值,一个是坐标,另一个是价值,然后有m组操作,每次操作给一个坐标,意思就是把当前这个坐标的点距离他最近的k个点(相等 ...
- 使用同步或异步的方式完成 I/O 访问和操作(Windows核心编程)
0x01 Windows 中对文件的底层操作 Windows 为了方便开发人员操作 I/O 设备(这些设备包括套接字.管道.文件.串口.目录等),对这些设备的差异进行了隐藏,所以开发人员在使用这些设备 ...
- Portswigger web security academy:Insecure deserialization
Insecure deserialization [toc] Modifying serialized objects 题目描述 此lab使用了 基于序列化的session机制 可以借此进行权限提升 ...
- Bugku-flag.php
flag.php 目录 flag.php 题目描述 解题过程 题目描述 点了login咋没反应 提示:hint 解题过程 fuzz 打开发现是个登录页面,点击login没反应,看了源码,action= ...
- 分解uber依赖注入库dig-源码分析
上一篇帖子 分解uber依赖注入库dig-使用篇 把如何使用dig进行代码示例说明,这篇帖子分析dig的源码,看他是如何实现依赖注入的. dig实现的中心思想:所有传入Provide的函数必须要有除e ...
- SSM项目使用Spring提供的测试
在测试类上添加注解@RunWith(SpringJUnit4ClassRunner.class)和@ContextConfiguration(locations = {"classpath: ...