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同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...
随机推荐
- VirtualBox虚拟机读取U盘
1 概述 使用VirtualBox虚拟机(系统Win10)读取宿主机(系统Manjaro)中的U盘. 2 安装扩展 戳这里下载对应版本的一个叫Oracle_VM_VirtualBox_Extensio ...
- (十三)VMware Harbor 身份验证模式
VMware Harbor 修改Harbor仓库admin用户 参考:https://blog.csdn.net/qq_40460909 https://blog.csdn.net/qq_404609 ...
- 图解高性能网络架构:Reactor 和 Proactor
小林,来了. 这次就来图解 Reactor 和 Proactor 这两个高性能网络模式. 别小看这两个东西,特别是 Reactor 模式,市面上常见的开源软件很多都采用了这个方案,比如 Redis.N ...
- 805. Split Array With Same Average
In a given integer array A, we must move every element of A to either list B or list C. (B and C ini ...
- java面试一日一题:binlog undolog redolog的区别
问题:请讲下mysql中binlog.undolog.redolog三种日志的区别 分析:mysql中这三种日志很常见,也是面试中涉及比较多的方面,要理解清楚这三种日志的定位及区别: 回答要点: 主要 ...
- 【JDK8】Java8 优雅的异步调用API CompletableFuture
1.CompletableFuture是什么? CompletableFuture是JDK8的新特性之一,是异步调用相关的API,用于简化异步调用,提高异步调用的效率 2.CompletableFut ...
- 从苏宁电器到卡巴斯基第25篇:难忘的三年硕士时光 III
阴差阳错,走上了讲师的道路 时间已经来到了2015年的1月,我的找工作之路也是屡败屡战,屡战屡败.金山.百度以及腾讯不约而同地不要我,使得我对于自己的未来充满了迷茫.尽管才研二而已,可是对于我这种没有 ...
- Hook android系统调用研究(一)
本文的博客链接:http://blog.csdn.net/qq1084283172/article/details/55657300 一.Android内核源码的编译环境 系统环境:Ubuntu 14 ...
- Day006 方法的定义和调用
方法的定义 Java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法: 方法包含一个方法头和一个方法体.下面是一个方法的所有部分: 修饰符:修饰符,这 ...
- 【maven】You may use+to add a project ro to let the plugin find all pom.xml files...
错误显示 解决方法 点击pom.xml,再Add as Maven Project 如果还不能解决,点击idea的log 复制报错(技巧:可以先将idea.log删除,比较好定位) Caused by ...