type
status
date
slug
summary
tags
category
icon
password
Property
Feb 24, 2025 11:31 AM
本文主要介绍JUC的扩展内容:并发类之阻塞队列
引题:文章前言,来点咬文嚼字说道说道,哈哈。与大家分享分享我的体会,先说知识,知识= 知 + 识。知重在理解,识重在实践。将所知思考推理,才能达到识的境界。所以我的体会是,不管是学什么,只看只能临时记忆,实践总结,才能入门识。所以知识不是背诵,而是理解与实践。技术亦是如此,技术=技 + 术。我认为,这两个字应该这么理解:技代表的是实际方案,术代表的是实际思想。所以学习技术本质就是通过看别人处理问题所使用的技巧来反推、反思别人处理问题时候思考的逻辑流程。闲谈结束,开始记录笔记。
JUC扩展类之阻塞队列
阻塞队列在JDK中也是蛮重要的,至少在很多地方都能看到他的身影。线程池七大参数就存在阻塞有界队列、生产者消费者模型就常用阻塞队列来进行业务演示、学习Servlet的时候曾试过用阻塞队列来充当限流工…
JDK中阻塞队列规范:JDK8到17未发生明显变化


JDK8中,当前常用的阻塞队列的结构组成

一、顶层接口Queue
二、阻塞队列
常见阻塞队列一般包括有界阻塞队列ArrayBlockingQueue、LinkedBlockingQueue、DelayQueue、PriorityBlockingQueue。其实除了Queue之后,还有Deque,所谓Deque就是Double-end Queue,也就是双端队列,具体解释可以看维基百科。目前我只回顾一下常见的阻塞队列其他的等遇到的时候会继续补充。
2.1 有界阻塞队列ArrayBlockingQueue
这是一个线程安全的阻塞队列,底层是通过ReentrantLock结合Condition来实现的,其中ReentrantLock保证了操作的原子性。

关于构造方法:三个构造方法都是不支持无参数构造的,构造此类必须指定界限,也就是底层依赖数组的容量大小,因此,此阻塞队列也被称之为阻塞队列。并且在默认的构造方法中,如果只传入容量大小,对应的锁是初始化的非公平的锁。
在看内部函数,对于添加,他是不允许Null值的。其次,他在使用Lock的时候是直接引用的初始化好了的锁。如果队列满了,会返回false,否则就会执行
enqueue
函数。将目标元素根据当前指针位置,装载进入底层的items
数组,如果putIndex
的在下一次自增为当前数组长度,将会将指针位置复位,成功添加元素之后,会通过Condition的signal()
函数来通知消费者消费。出队列反之亦然。小结:ArrayBlockingQueue使用独占锁ReentrantLock实现线程安全,入队和出队操作使用同一个锁对象,也就是只能有一个线程可以进行入队或者出队操作;这也就意味着生产者和消费者无法并行操作,在高并发场景下会成为性能瓶颈。
2.2 LinkedBlockingQueue 无界阻塞队列解读
LinkedBlockingQueue之所以被称之为无界队列,是因为默认构造函数底层设置容量的时候使用了Integer的最大值,这种数量级一般是达不到的,内存也放不下…所以相当于是无界队列。但是可以构造成有界队列,可以通过提供的另一个构造方式来实现。值得注意的是,与ArrayBlockingQueue不同的是,ArrayBlockingQueue底层实现是依赖于数组这种基本数据结构,而LinkedBlockingQueue是依赖于链表结构。这也是核心区别。
与ArrayBlockingQueue不同的是,LinkedBlockingQueue在锁上是有区别的,生产消费使用不同的锁,生产与消费并发的时候不会发生阻塞,性能提升,这也是为什么线程池默认将此队列作为阻塞队列,锁分离能支撑他的高性能表现。
2.3 DelayQueue
DelayQueue 是一个支持延时获取元素的阻塞队列, 内部采用优先队列 PriorityQueue 存储元素,同时元素必须实现 Delayed 接口;在创建元素时可以指定多久才可以从队列中获取当前元素,只有在延迟期满时才能从队列中提取元素。延迟队列的特点是:不是先进先出,而是会按照延迟时间的长短来排序,下一个即将执行的任务会排到队列的最前面。

入队put源码
出队take源码
流程如下:

- 作者:fntp
- 链接:https://polofox.com/article/juc-core-6
- 声明:本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
相关文章