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()

上面的方法的四种行为分别的含义是

  1. 抛出异常: 如果调用方法后不能立即响应结果(空队列或满队列),则抛出异常。
  2. 返回特定值: 如果调用方法后不能立即响应结果(空队列或满队列),则返回特定的值(通常是true/false),true表示方法执行成功,否则表示方法执行失败。
  3. 阻塞后一直等待: 如果调用方法后不能立即响应结果(空队列或满队列),该方法将被阻塞一直处于等待状态。
  4. 阻塞后等待超时: 如果调用方法后不能立即响应结果(空队列或满队列),该方法将在一定时间范围内被阻塞等待,也就是在超时时间范围内阻塞。当超出超时时间之后,方法线程将不再阻塞,而是返回一个特定的值(通常是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() 方法将返回队列目前还剩多少个可用空间用于放入新的对象。剩余空间容量=队列的总容量-已经被占用的空间数量

欢迎关注我的博客,里面有很多精品合集

  • 本文转载注明出处(必须带连接,不能只转文字):字母哥博客

觉得对您有帮助的话,帮我点赞、分享!您的支持是我不竭的创作动力! 。另外,笔者最近一段时间输出了如下的精品内容,期待您的关注。

java并发编程工具类JUC第一篇:BlockingQueue阻塞队列的更多相关文章

  1. java并发编程工具类JUC第二篇:ArrayBlockingQueue

    类ArrayBlockingQueue是BlockingQueue接口的实现类,它是有界的阻塞队列,内部使用数组存储队列元素.这里的"有界"是指存储容量存在上限,不能无限存储元素. ...

  2. java并发编程工具类JUC第八篇:ConcurrentHashMap

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  3. java并发编程工具类JUC第七篇:BlockingDeque双端阻塞队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue.LinkedBlockingQueue.Priorit ...

  4. java并发编程工具类JUC第四篇:LinkedBlockingQueue链表队列

    在之前的文章中已经为大家介绍了java并发编程的工具:BlockingQueue接口.ArrayBlockingQueue.DelayQueue. LinkedBlockingQueue 队列是Blo ...

  5. java并发编程工具类JUC第三篇:DelayQueue延时队列

    DelayQueue 是BlockingQueue接口的实现类,它根据"延时时间"来确定队列内的元素的处理优先级(即根据队列元素的"延时时间"进行排序).另一层 ...

  6. Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo

    Java并发编程工具类 CountDownLatch CyclicBarrier Semaphore使用Demo CountDownLatch countDownLatch这个类使一个线程等待其他线程 ...

  7. java并发编程工具类辅助类:CountDownLatch、CyclicBarrier和 Semaphore

    在java 1.5中,提供了一些非常有用的辅助类来帮助我们进行并发编程,比如CountDownLatch,CyclicBarrier和Semaphore,今天我们就来学习一下这三个辅助类的用法. 以下 ...

  8. 【Java并发编程实战】----- AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形.其主要从两方面进行了改造:节点的结构与节点等待机制.在结构上引入了头 ...

  9. 【Java并发编程实战】—– AQS(四):CLH同步队列

    在[Java并发编程实战]-–"J.U.C":CLH队列锁提过,AQS里面的CLH队列是CLH同步锁的一种变形. 其主要从双方面进行了改造:节点的结构与节点等待机制.在结构上引入了 ...

随机推荐

  1. VirtualBox虚拟机读取U盘

    1 概述 使用VirtualBox虚拟机(系统Win10)读取宿主机(系统Manjaro)中的U盘. 2 安装扩展 戳这里下载对应版本的一个叫Oracle_VM_VirtualBox_Extensio ...

  2. (十三)VMware Harbor 身份验证模式

    VMware Harbor 修改Harbor仓库admin用户 参考:https://blog.csdn.net/qq_40460909 https://blog.csdn.net/qq_404609 ...

  3. 图解高性能网络架构:Reactor 和 Proactor

    小林,来了. 这次就来图解 Reactor 和 Proactor 这两个高性能网络模式. 别小看这两个东西,特别是 Reactor 模式,市面上常见的开源软件很多都采用了这个方案,比如 Redis.N ...

  4. 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 ...

  5. java面试一日一题:binlog undolog redolog的区别

    问题:请讲下mysql中binlog.undolog.redolog三种日志的区别 分析:mysql中这三种日志很常见,也是面试中涉及比较多的方面,要理解清楚这三种日志的定位及区别: 回答要点: 主要 ...

  6. 【JDK8】Java8 优雅的异步调用API CompletableFuture

    1.CompletableFuture是什么? CompletableFuture是JDK8的新特性之一,是异步调用相关的API,用于简化异步调用,提高异步调用的效率 2.CompletableFut ...

  7. 从苏宁电器到卡巴斯基第25篇:难忘的三年硕士时光 III

    阴差阳错,走上了讲师的道路 时间已经来到了2015年的1月,我的找工作之路也是屡败屡战,屡战屡败.金山.百度以及腾讯不约而同地不要我,使得我对于自己的未来充满了迷茫.尽管才研二而已,可是对于我这种没有 ...

  8. Hook android系统调用研究(一)

    本文的博客链接:http://blog.csdn.net/qq1084283172/article/details/55657300 一.Android内核源码的编译环境 系统环境:Ubuntu 14 ...

  9. Day006 方法的定义和调用

    方法的定义 Java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法: 方法包含一个方法头和一个方法体.下面是一个方法的所有部分: 修饰符:修饰符,这 ...

  10. 【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 ...