一、PriorityBlockingQueue 的put方法底层源码
PriorityBlockingQueue 的 put 方法用于将元素插入队列。由于 PriorityBlockingQueue 是一个无界队列,put 方法不会阻塞,总是会成功插入元素
1、put 方法的作用
-
将元素插入队列。
-
由于队列无界,put 方法不会阻塞,总是会成功插入元素。
-
插入后,队列会根据元素的优先级重新排序。
2、put 方法的源码
以下是 PriorityBlockingQueue 中 put 方法的源码(基于 JDK 17):
可以看到,put 方法直接调用了 offer 方法。因此,我们需要进一步分析 offer 方法的实现。
3、offer 方法的源码
以下是 PriorityBlockingQueue 中 offer 方法的源码:
4、源码解析
(1)参数检查
- PriorityBlockingQueue 不允许插入 null 元素,如果传入 null,会抛出 NullPointerException。
(2)获取锁
-
lock 是 PriorityBlockingQueue 的成员变量,用于控制插入和移除操作的并发访问。
-
调用 lock() 方法获取锁。
(3)检查队列容量
-
size 是当前队列中的元素数量。
-
如果队列已满(n >= queue.length),调用 grow() 方法扩容。
-
grow() 方法的实现:
(4)插入元素并调整堆结构
- siftUp 方法将元素插入堆中,并调整堆结构以维持堆的性质:
siftUp 方法通过比较元素和其父节点,将元素插入到正确的位置,以维持堆的性质(最小堆或最大堆)
(5)更新队列大小
- 将队列大小加 1。
(6)唤醒消费者线程
- 如果队列之前为空,调用 notEmpty.signal() 唤醒可能正在等待的消费者线程。
(7)释放锁
- 在 finally 块中释放锁,确保锁一定会被释放,避免死锁。
(8)返回结果
- 由于队列无界,offer 方法总是返回 true。
二、关键点总结
-
无界队列:PriorityBlockingQueue 是无界队列,put 方法不会阻塞。
-
堆结构:使用堆数据结构维护元素的优先级顺序。
-
线程安全:通过 ReentrantLock 保证线程安全。
-
动态扩容:当队列容量不足时,会自动扩容。
三、示例流程图
以下是 put 方法的执行流程图:
1、检查元素是否为 null。
2、获取锁。
3、检查队列容量,如果不足则扩容。
4、将元素插入堆中,并调整堆结构。
5、更新队列大小。
6、如果队列之前为空,唤醒消费者线程。
7、释放锁。
8、返回 true。