【小家Java】Java优先队列PriorityQueue、PriorityBlockingQueue使用示例
每篇一句
一直觉得程序员的核心是用抽象和自动化来降低成本和快速实现更多的价值。
而中间件则可以抽象出通用的能力为业务同学赋能,让业务同学专业做业务,实现更大的业务价值~~
前言
我们知道队列是遵循先进先出(First-In-First-Out
)模式的,但有些时候需要在队列中基于优先级处理对象。
为什么优先级队列,其实很好理解。比如银行的VIP客户、各大机场的VIP客户的优先登机等,都是优先级队列的体现。而正常排队的都属于普通队列~
PriorityQueue
PriorityQueue
类在Java1.5
中引入的,它是Java集合框架的一部分。PriorityQueue是基于优先堆的一个*队列
,它是一个Queue
默认情况下它 根据自然排序,当然我们也可以定制比较器,自行自定义排序,从而实现自己的优先级逻辑。
// @since 1.5
public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {
// 构造函数
public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityQueue(int initialCapacity) {
this(initialCapacity, null);
}
//@since 1.8
public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}
// 自己指定初始化因子,指定比较器
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator) {
// initialCapacity 不能小于1
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.queue = new Object[initialCapacity];
this.comparator = comparator;
}
//
public PriorityQueue(Collection<? extends E> c) {...}
public PriorityQueue(SortedSet<? extends E> c) {...}
...
}
// @since 1.5 AbstractQueue这个类也是1.5后出现的 我们发现它还继承自AbstractCollection 所以它也是个Collection
public abstract class AbstractQueue<E> extends AbstractCollection<E> implements Queue<E> {
...
}
Demo Show:
public static void main(String[] args) {
PriorityQueue<String> priorityQueue = new PriorityQueue<>();
priorityQueue.add("orange");
priorityQueue.add("fig");
priorityQueue.add("watermelon");
priorityQueue.add("lemon");
while (priorityQueue.size() != 0) {
System.out.println(priorityQueue.remove());
}
}
输出:
fig
lemon
orange
watermelon
没有指定比较器,所以就按照自然排序的规则排了。下面我们自己指定一个比较器试试:
// 指定一个倒序输出的比较器
PriorityQueue<String> priorityQueue = new PriorityQueue<>(Comparator.reverseOrder());
输出:
fig
lemon
orange
watermelon
因此我们看到优先级队列的使用,使用起来还是非常的简单的。
优先队列不允许空值,而且不支持non-comparable(不可比较)的对象,比如用户自定义的类。
注意:此处需要注意的是,你是基于某个字段做优先级排序,只需要那个字段可比较即可,而不需要整个类都实现比较器接口
优先队列的头是基于自然排序或者Comparator排序的最小元素。
如果有多个对象拥有同样的排序,那么就可能随机地取其中任意一个
。当我们获取队列时,返回队列的头对象。
PriorityQueue
是非线程安全的,所以Java提供了PriorityBlockingQueue
(实现BlockingQueue
接口)用于Java多线程环境。
PriorityBlockingQueue
在之前有篇博文:
【小家java】BlockingQueue阻塞队列详解以及5大实现(ArrayBlockingQueue、DelayQueue、LinkedBlockingQueue…)
本文重点不介绍它阻塞的特性,而是介绍它优先级队列的使用办法。
它是一个*有序的阻塞队列
,排序规则和之前介绍的PriorityQueue一致,只是增加了阻塞操作
。同样的该队列不支持插入null元素,同时不支持插入非comparable的对象。
该类不保证同等优先级的元素顺序,如果你想要强制顺序,就需要考虑自定义顺序或者是Comparator使用第二个比较属性
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
implements BlockingQueue<E>, java.io.Serializable {
public PriorityBlockingQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}
public PriorityBlockingQueue(int initialCapacity) {
this(initialCapacity, null);
}
public PriorityBlockingQueue(int initialCapacity, Comparator<? super E> comparator) {
if (initialCapacity < 1)
throw new IllegalArgumentException();
this.lock = new ReentrantLock();
this.notEmpty = lock.newCondition();
this.comparator = comparator;
this.queue = new Object[initialCapacity];
}
public PriorityBlockingQueue(Collection<? extends E> c) {...}
...
}
它的构造函数和PriorityQueue
基本一样,因此使用方式其实也是差不多的。只是它增加了对多线程的处理、以及对阻塞队列特性的支持~~~~
Demo Show:
public static void main(String[] args) {
// 注意的是:它没有提供和PriorityQueue一样的只提供比较器的构造函数,我个人觉得是JDK忘了~~~~
PriorityBlockingQueue<String> priorityQueue = new PriorityBlockingQueue<>(11,Comparator.reverseOrder());
priorityQueue.add("orange");
priorityQueue.add("fig");
priorityQueue.add("watermelon");
priorityQueue.add("lemon");
while (priorityQueue.size() != 0) {
System.out.println(priorityQueue.remove());
}
}
输出:
watermelon
orange
lemon
fig
可以看出,使用方式几乎一样~~~
总结
(阻塞)队列能解决我们最常规的排队的问题,而优先级队这种数据结构能够解决我们业务中可能会用到的VIP排队问题。
比如有个常规的使用场景:优先级消息(MQ消息),有的就是基于JDK的优先级队列来实现的~~~
知识交流
若群二维码失效,请加微信号(或者扫描下方二维码):fsx641385712。
并且备注:“java入群” 字样,会手动邀请入群