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)中的队列类相关推荐

  1. 并发容器(J.U.C)中的集合类

    同步容器是通过synchronized来实现同步的,所以性能较差.而且同步容器也并不是绝对线程安全的,在一些特殊情况下也会出现线程不安全的行为.那么有没有更好的方式代替同步容器呢?----> 那 ...

  2. 死磕Java并发:J.U.C之阻塞队列:ArrayBlockingQueue

    作者:chenssy 来源:Java技术驿站 ArrayBlockingQueue,一个由数组实现的有界阻塞队列.该队列采用FIFO的原则对元素进行排序添加的. ArrayBlockingQueue为 ...

  3. 并发容器J.U.C -- AQS组件(一)

    AQS简介 AQS全名:AbstractQueuedSynchronizer,是并发容器J.U.C(java.lang.concurrent)下locks包内的一个类.它实现了一个FIFO的队列.底层 ...

  4. java高并发(十二)并发容器J.U.C

    并发容器是JDK提供的一个包名:java.util.concurrent ArrayList -> CopyOnWriteArrayList CopyOnWriteArrayList是线程安全的 ...

  5. J .U.C 中的原子操作类

    由于变量类型的关系,在J.U.C中提供了12个原子操作的类.这12个类可以分为四大类 1. 原子更新基本类型 AtomicBoolean.AtomicInteger.AtomicLong 2. 原子更 ...

  6. java高并发(十三)并发容器J.U.C--AQS

    AbstractQueueSynchronizer (AQS) J.U.C 大大提高了java并发的性能,而AQS则是J.U.C的核心. AQS底层使用双向列表(队列的一种实现). 使用Node实现F ...

  7. Java并发容器J.U.C

    J.U.C是java.util.concurrent的简写,里面提供了很多线程安全的集合. CopyOnWriteArrayList介绍 CopyOnWriteArrayList相比于ArrayLis ...

  8. 死磕Java并发:J.U.C之阻塞队列:LinkedBlockingDeque

    作者:chenssy 来源:Java技术驿站 前面的BlockingQueue都是单向的FIFO队列,而LinkedBlockingDeque则是一个由链表组成的双向阻塞队列,双向队列就意味着可以从对 ...

  9. 死磕Java并发:J.U.C之阻塞队列:PriorityBlockingQueue

    作者:chenssy 来源:Java技术驿站 我们知道线程Thread可以调用setPriority(int newPriority)来设置优先级的,线程优先级高的线程先执行,优先级低的后执行.而前面 ...

最新文章

  1. 数据有价——数据资产定价研究初探
  2. 人工智能三大驱动力背后的CMOS传感器
  3. 2 0 2 0 年 第 十 一 届 蓝 桥 杯 - 国赛 - CC++大学B组 - B.扩散
  4. 洛谷 - P2765 魔术球问题(最大流+残余网络上的最大流+路径打印)
  5. 设置linux文件系统密码,busybox 文件系统设置 登陆 login 密码 password shadow
  6. 逗号后面统一加空格_用99个空格来提取Excel单元格数据,真的是脑洞大开!!!...
  7. BZOJ 2660 (BJOI 2012) 最多的方案
  8. [Perl系列—] 2. Perl 中的引用用法
  9. c调用python函数_python - Linux C调用Python 函数
  10. 54.购物流程(1)---simple product
  11. 大致看了下伍德里奇的《计量经济学导论》
  12. 贴片元器件焊接经验及总结
  13. 幻灯片母板_如何在Microsoft PowerPoint中创建幻灯片母版
  14. wps目录怎么加一条_WPS中如何正确插入目录_WPS怎么做目录
  15. 【GNN报告】复旦大学许嘉蓉:基于图数据的鲁棒机器学习
  16. 刚刚整理好-汉字转拼音缩写的函数(C#)
  17. OSChina 周五乱弹 —— 生命诚可贵,改 BUG 价更高?
  18. 转载:渗透测试方法论(阅读)
  19. 过程计算机系统 pcs,过程控制系统(PCS)
  20. 2022年K1刷第三方固件教程

热门文章

  1. visual studio code更新
  2. 演示对sys用户和普通用户进行审计的示例
  3. mysql在恢复数据时出现“table full”报错
  4. 被360整的体无完肤,我真的怒了!
  5. NSMutableString可变字符串
  6. Outlook2010新建域内Exchang邮箱的另一种方法
  7. SQL Server 2000优化SELECT语句方法
  8. 基于 HTML5 Canvas 实现的文字动画特效
  9. mybatis生成工具
  10. Android Studio下“Error:Could not find com.android.tools.build:gradle:2.2.1”的解决方法