并发容器(J.U.C)中的队列类
JUC包下的容器类分为两部分,一部分是并发集合类,一部分是并发队列类,其中并发集合类可以解决我们集合使用过程中的多线程并发问题,而并发队列类则主要被当做阻塞队列使用,是线程池中的关键参数之一。
文章目录
- 并发队列
- BlockingQueue简介
- 阻塞队列的4种基本操作
- JDK 7提供的7个阻塞队列
- 本文小结
并发队列
并发队列中主要的类如下
BlockingQueue简介
最常用的"生产者-消费者"问题中,队列通常被视作线程间操作的数据容器,这样,可以对各个模块的业务功能进行解耦,生产者将“生产”出来的数据放置在数据容器中,而消费者仅仅只需要在“数据容器”中进行获取数据即可,这样生产者线程和消费者线程就能够进行解耦,只专注于自己的业务功能即可。阻塞队列(BlockingQueue)被广泛使用在“生产者-消费者”问题中,其原因是BlockingQueue提供了可阻塞的插入和移除的方法。当队列容器已满,生产者线程会被阻塞,直到队列未满;当队列容器为空时,消费者线程会被阻塞,直至队列非空时为止。.阻塞队列常用于生产者和消费者的场景,生产者是向队列里添加元素的线程,消费者是从队列里取元素的线程。阻塞队列就是生产者用来存放元素、消费者用来获取元素的容器。
阻塞队列的4种基本操作
抛出异常
- 当队列满时,如果再往队列里插入元素,会抛出IllegalStateException(“Queuefull”)异常。
- 当队列空时,从队列里获取元素会抛出NoSuchElementException异常。
返回特殊值
- 当往队列插入元素时,会返回元素是否插入成功,成功返回true。如果是移除方法,则是从队列里取出一个元素,如果没有则返回null。
一直阻塞
- 当阻塞队列满时,如果生产者线程往队列里put元素,队列会一直阻塞生产者线程,直到队列可用或者响应中断退出。
- 当队列空时,如果消费者线程从队列里take元素,队列会阻塞住消费者线程,直到队列不为空。
超时退出
- 当阻塞队列满时,如果生产者线程往队列里插入元素,队列会阻塞生产者线程一段时间,如果超过了指定的时间,生产者线程就会退出。
JDK 7提供的7个阻塞队列
常用的BlockingQueue
实现BlockingQueue接口的有ArrayBlockingQueue, DelayQueue, LinkedBlockingDeque, LinkedBlockingQueue, LinkedTransferQueue, PriorityBlockingQueue, SynchronousQueue,而这几种常见的阻塞队列也是在实际编程中会常用的,下面对这几种常见的阻塞队列进行说明:
1.ArrayBlockingQueue
ArrayBlockingQueue是由数组实现的有界阻塞队列。该队列命令元素FIFO(先进先出)。因此,对头元素时队列中存在时间最长的数据元素,而对尾数据则是当前队列最新的数据元素。ArrayBlockingQueue可作为“有界数据缓冲区”,生产者插入数据到队列容器中,并由消费者提取。ArrayBlockingQueue一旦创建,容量不能改变。
当队列容量满时,尝试将元素放入队列将导致操作阻塞;尝试从一个空队列中取一个元素也会同样阻塞。
ArrayBlockingQueue默认情况下不能保证线程访问队列的公平性,所谓公平性是指严格按照线程等待的绝对时间顺序,即最先等待的线程能够最先访问到ArrayBlockingQueue。而非公平性则是指访问ArrayBlockingQueue的顺序不是遵守严格的时间顺序,有可能存在,一旦ArrayBlockingQueue可以被访问时,长时间阻塞的线程依然无法访问到ArrayBlockingQueue。如果保证公平性,通常会降低吞吐量。如果需要获得公平性的ArrayBlockingQueue,可采用如下代码:
ArrayBlockingQueue fairQueue = new ArrayBlockingQueue(1000,true);
2.LinkedBlockingQueue
LinkedBlockingQueue是用链表实现的有界阻塞队列,同样满足FIFO的特性,与ArrayBlockingQueue相比起来具有更高的吞吐量,为了防止LinkedBlockingQueue容量迅速增,损耗大量内存。通常在创建LinkedBlockingQueue对象时,会指定其大小,如果未指定,容量等于Integer.MAX_VALUE。
3.PriorityBlockingQueue
PriorityBlockingQueue是一个支持优先级的无界阻塞队列。默认情况下元素采取自然顺序升序排列。也可以自定义类实现compareTo()方法来指定元素排序规则,或者初始化PriorityBlockingQueue时,指定构造参数Comparator来对元素进行排序。需要注意的是不能保证同优先级元素的顺序。
4.SynchronousQueue
SynchronousQueue每个插入操作必须等待另一个线程进行相应的删除操作,因此,SynchronousQueue实际上没有存储任何数据元素,因为只有线程在删除数据时,其他线程才能插入数据,同样的,如果当前有线程在插入数据时,线程才能删除数据。SynchronousQueue也可以通过构造器参数来为其指定公平性。
public SynchronousQueue(boolean fair) {transferer = fair new TransferQueue() : new TransferStack();
}
5.LinkedTransferQueue
LinkedTransferQueue是一个由链表数据结构构成的无界阻塞队列,由于该队列实现了TransferQueue接口,与其他阻塞队列相比主要有以下不同的方法:
transfer(E e)
如果当前有线程(消费者)正在调用take()方法或者可延时的poll()方法进行消费数据时,生产者线程可以调用transfer方法将数据传递给消费者线程。如果当前没有消费者线程的话,生产者线程就会将数据插入到队尾,直到有消费者能够进行消费才能退出;
tryTransfer(E e)
tryTransfer方法如果当前有消费者线程(调用take方法或者具有超时特性的poll方法)正在消费数据的话,该方法可以将数据立即传送给消费者线程,如果当前没有消费者线程消费数据的话,就立即返回false。因此,与transfer方法相比,transfer方法是必须等到有消费者线程消费数据时,生产者线程才能够返回。而tryTransfer方法能够立即返回结果退出。
tryTransfer(E e,long timeout,imeUnit unit)
与transfer基本功能一样,只是增加了超时特性,如果数据才规定的超时时间内没有消费者进行消费的话,就返回false。
6.LinkedBlockingDeque
LinkedBlockingDeque是基于链表数据结构的有界阻塞双端队列,如果在创建对象时为指定大小时,其默认大小为Integer.MAX_VALUE。与LinkedBlockingQueue相比,主要的不同点在于,LinkedBlockingDeque具有双端队列的特性。
所谓双向队列指的是可以从队列的两端插入和移出元素。双向队列因为多了一个操作队列的入口,在多线程同时入队时,也就减少了一半的竞争。相比其他的阻塞队列,LinkedBlockingDeque多了addFirst、addLast、offerFirst、offerLast、peekFirst和peekLast等方法,以First单词结尾的方法,表示插入、获取(peek)或移除双端队列的第一个元素。以Last单词结尾的方法,表示插入、获取或移除双端队列的最后一个元素。
7.DelayQueue
DelayQueue是一个存放实现Delayed接口的数据的无界阻塞队列,只有当数据对象的延时时间达到时才能插入到队列进行存储。如果当前所有的数据都还没有达到创建时所指定的延时期,则队列没有队头,并且线程通过poll等方法获取数据元素则返回null。所谓数据延时期满时,则是通过Delayed接口的getDelay(TimeUnit.NANOSECONDS)来进行判定,如果该方法返回的是小于等于0则说明该数据元素的延时期已满。
DelayQueue是一个支持延时获取元素的无界阻塞队列。队列使用PriorityQueue来实现。队列中的元素必须实现Delayed接口,在创建元素时可以指定多久才能从队列中获取当前元素。只有在延迟期满时才能从队列中提取元素。
本文小结
本文介绍了juc中几种常见的阻塞队列,这些阻塞队列在线程池中会被用到,在日常开发中也会用到。
并发容器(J.U.C)中的队列类相关推荐
- 并发容器(J.U.C)中的集合类
同步容器是通过synchronized来实现同步的,所以性能较差.而且同步容器也并不是绝对线程安全的,在一些特殊情况下也会出现线程不安全的行为.那么有没有更好的方式代替同步容器呢?----> 那 ...
- 死磕Java并发:J.U.C之阻塞队列:ArrayBlockingQueue
作者:chenssy 来源:Java技术驿站 ArrayBlockingQueue,一个由数组实现的有界阻塞队列.该队列采用FIFO的原则对元素进行排序添加的. ArrayBlockingQueue为 ...
- 并发容器J.U.C -- AQS组件(一)
AQS简介 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下locks包内的一个类.它实现了一个FIFO的队列.底层 ...
- java高并发(十二)并发容器J.U.C
并发容器是JDK提供的一个包名:java.util.concurrent ArrayList -> CopyOnWriteArrayList CopyOnWriteArrayList是线程安全的 ...
- J .U.C 中的原子操作类
由于变量类型的关系,在J.U.C中提供了12个原子操作的类.这12个类可以分为四大类 1. 原子更新基本类型 AtomicBoolean.AtomicInteger.AtomicLong 2. 原子更 ...
- java高并发(十三)并发容器J.U.C--AQS
AbstractQueueSynchronizer (AQS) J.U.C 大大提高了java并发的性能,而AQS则是J.U.C的核心. AQS底层使用双向列表(队列的一种实现). 使用Node实现F ...
- Java并发容器J.U.C
J.U.C是java.util.concurrent的简写,里面提供了很多线程安全的集合. CopyOnWriteArrayList介绍 CopyOnWriteArrayList相比于ArrayLis ...
- 死磕Java并发:J.U.C之阻塞队列:LinkedBlockingDeque
作者:chenssy 来源:Java技术驿站 前面的BlockingQueue都是单向的FIFO队列,而LinkedBlockingDeque则是一个由链表组成的双向阻塞队列,双向队列就意味着可以从对 ...
- 死磕Java并发:J.U.C之阻塞队列:PriorityBlockingQueue
作者:chenssy 来源:Java技术驿站 我们知道线程Thread可以调用setPriority(int newPriority)来设置优先级的,线程优先级高的线程先执行,优先级低的后执行.而前面 ...
最新文章
- 数据有价——数据资产定价研究初探
- 人工智能三大驱动力背后的CMOS传感器
- 2 0 2 0 年 第 十 一 届 蓝 桥 杯 - 国赛 - CC++大学B组 - B.扩散
- 洛谷 - P2765 魔术球问题(最大流+残余网络上的最大流+路径打印)
- 设置linux文件系统密码,busybox 文件系统设置 登陆 login 密码 password shadow
- 逗号后面统一加空格_用99个空格来提取Excel单元格数据,真的是脑洞大开!!!...
- BZOJ 2660 (BJOI 2012) 最多的方案
- [Perl系列—] 2. Perl 中的引用用法
- c调用python函数_python - Linux C调用Python 函数
- 54.购物流程(1)---simple product
- 大致看了下伍德里奇的《计量经济学导论》
- 贴片元器件焊接经验及总结
- 幻灯片母板_如何在Microsoft PowerPoint中创建幻灯片母版
- wps目录怎么加一条_WPS中如何正确插入目录_WPS怎么做目录
- 【GNN报告】复旦大学许嘉蓉:基于图数据的鲁棒机器学习
- 刚刚整理好-汉字转拼音缩写的函数(C#)
- OSChina 周五乱弹 —— 生命诚可贵,改 BUG 价更高?
- 转载:渗透测试方法论(阅读)
- 过程计算机系统 pcs,过程控制系统(PCS)
- 2022年K1刷第三方固件教程
热门文章
- visual studio code更新
- 演示对sys用户和普通用户进行审计的示例
- mysql在恢复数据时出现“table full”报错
- 被360整的体无完肤,我真的怒了!
- NSMutableString可变字符串
- Outlook2010新建域内Exchang邮箱的另一种方法
- SQL Server 2000优化SELECT语句方法
- 基于 HTML5 Canvas 实现的文字动画特效
- mybatis生成工具
- Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法