priorityblockingqueue通过二叉堆、reentrantlock与condition、cas扩容三重机制实现无界优先级队列,支持高并发下o(log n)插入/删除与o(1)查首,适用于告警分发、vip订单、延迟任务等场景。

PriorityBlockingQueue 通过“二叉堆 + 显式锁 + 条件等待”三重机制,在无界前提下兼顾排序性与线程安全性,直接解决高并发场景中任务按优先级有序消费的竞争问题。
二叉堆保障插入/出队的优先级语义
它内部用数组模拟最小堆(默认),每个元素位置满足:queue[i] ≤ queue[2i+1] 且 queue[i] ≤ queue[2i+2]。这意味着:
- peek() 总是 O(1) 返回当前最高优先级(即最小键值)元素
- offer() 插入后执行“上浮(sift-up)”,从末尾逐层与父节点比较交换,维持堆序,时间复杂度 O(log n)
- poll()/take() 移除堆顶后执行“下沉(sift-down)”,用末尾元素填充根位,再向下交换至合理位置,同样 O(log n)
- 不依赖 FIFO,也不保证同优先级元素的相对顺序——这恰是优先级调度的合理取舍
ReentrantLock + Condition 消除并发访问冲突
与非线程安全的 PriorityQueue 不同,它用单一可重入锁保护所有公共操作:
- 所有 offer、poll、take、peek 等方法均先 lock.lock(),避免多个线程同时修改 queue 数组或 size 变量
- 当 take() 调用时发现 size == 0,线程在 notEmpty 条件上 await(),挂起并释放锁;新元素 offer 成功后调用 notEmpty.signal() 唤醒等待者
- 没有 notFull 条件——因为它是无界队列,offer 永远不会阻塞(仅在内存耗尽时抛 OOM)
扩容与竞争控制避免写写冲突
数组容量不足时,扩容不是简单加锁后复制,而是引入 CAS 自旋锁 allocationSpinLock:
- 多个线程同时触发扩容时,仅一个能通过 compareAndSet(0, 1) 获取扩容权,其余自旋等待
- 避免了锁粒度过粗导致的扩容瓶颈,也防止了多线程并发 resize 引发数组覆盖或丢失
- 扩容后仍保持堆结构:新数组拷贝旧元素,再对新增部分做 heapify(但通常只对新增节点局部 sift)
适用典型任务调度场景
它不适用于需要严格时间顺序或公平性的场合,但特别匹配以下需求:
- 告警系统:按严重等级(P0 > P1 > P2)分发处理,P0 告警永远最先被消费
- 订单履约:VIP 用户订单设置更高 priority 值,确保资源倾斜
- 延迟任务(配合自定义 Comparator):将 Runnable 封装为 DelayTask,按 delayMs 升序排列,再由调度线程轮询 take()
- 多生产者单/多消费者模型:任意数量线程 submit 任务,工作线程统一 take(),天然负载均衡+优先级驱动










