发布于2026-07-08 阅读(0)
扫一扫,手机访问
在 Ja va 并发工具包中,PriorityBlockingQueue 是一个相当特别的存在——它结合了优先级排序和阻塞队列的能力。简单来说,就是基于优先级堆实现的无界阻塞队列。核心特性可以归结为以下几点:

底层用数组实现了一个二叉堆——默认是最小堆,堆顶存放最小元素。通过简单的索引关系就能维护父子节点:
// 父节点索引 parent(i) = (i-1) >>> 1 // 左子节点索引 leftChild(i) = 2*i + 1 // 右子节点索引 rightChild(i) = 2*i + 2
举个例子,数组 `` 对应的堆结构,从上图就能看得一目了然。
private transient Object[] queue; // 存储元素的数组 private transient int size; // 当前元素数量 private final ReentrantLock lock; // 主锁 private final Condition notEmpty; // 队列非空条件 private transient Comparator super E> comparator; // 比较器
扩容是动态进行的,规则也分情况而定:
有意思的是,扩容是通过 CAS 操作(allocationSpinLock)来控制的,这样能避免线程阻塞——算是一个无锁扩容的小技巧。
public boolean offer(E e) {
if (e == null) throw new NullPointerException();
lock.lock();
try {
// 检查是否需要扩容
if (size >= queue.length) grow();
// 上浮操作维护堆性质
siftUp(size, e);
size++;
notEmpty.signal(); // 唤醒等待的消费者
return true;
} finally {
lock.unlock();
}
}
关键步骤其实就三个:扩容检查 → 上浮调整堆结构 → 唤醒消费者线程。
public E take() throws InterruptedException {
lock.lockInterruptibly();
try {
while (size == 0) notEmpty.await(); // 队列空时阻塞
return dequeue();
} finally {
lock.unlock();
}
}
private E dequeue() {
E result = (E) queue; // 取出堆顶元素
E x = (E) queue@ref; // 最后一个元素移到堆顶
queue= null; // 清除原堆顶
if (size > 0) siftDown(0, x); // 下沉操作维护堆性质
return result;
}
出队的流程也很清晰:阻塞等待 → 取出堆顶 → 下沉调整堆结构。
这里用的是单锁设计,所有修改操作(插入/删除)共享同一把 ReentrantLock。好处是实现简单,但坏处也很明显——在高并发场景下,单一把锁可能会成为瓶颈。条件变量方面,只用了 notEmpty 来做消费者等待,没有 notFull——毕竟是无界的队列。
// 自定义任务类(降序优先级) class Task implements Comparable{ private int priority; public Task(int priority) { this.priority = priority; } @Override public int compareTo(Task o) { return Integer.compare(o.priority, this.priority); // 降序排列 } } // 使用示例 PriorityBlockingQueue queue = new PriorityBlockingQueue<>(); queue.put(new Task(3)); // 插入低优先级任务 queue.put(new Task(1)); // 插入高优先级任务 Task task = queue.take(); // 取出优先级1的任务
注意这里自定义的 compareTo 做了降序排列,这样才能让高优先级的任务先出队。
| 特性 | PriorityBlockingQueue | ArrayBlockingQueue | ConcurrentLinkedQueue |
|---|---|---|---|
| 容量 | 无界 | 有界 | 无界 |
| 排序 | 支持优先级 | FIFO | 无序 |
| 锁机制 | 单锁 | 单锁 | 无锁 |
| 适用场景 | 优先级调度 | 有界缓冲 | 高并发无序队列 |
总的来说,PriorityBlockingQueue 非常适合用来实现基于优先级的并发任务处理。不过它的无界特性是把双刃剑——带来了灵活性,也带来了内存风险。在需要严格控制容量的场景中,还是考虑 ArrayBlockingQueue 或分片策略更稳妥。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8