优先队列是根据二叉堆实现的,二叉堆的数据结构如下图所示:
二叉堆分为两种类型:一种是最大堆一种是最小堆。以上展示的是最大堆,在最大堆中,任意一个父节点的值都大于等于它左右子节点的值。
因为优先队列是基于二叉堆实现的,因此它可以将优先级最好的元素先出队。
接下来我们来演示一下优先队列的使用:
import java.util.PriorityQueue; public class PriorityQueueTest { // 自定义的实体类 static class Viper { private int id; // id private String name; // 名称 private int level; // 等级 public Viper(int id, String name, int level) { this.id = id; this.name = name; this.level = level; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getLevel() { return level; } public void setLevel(int level) { this.level = level; } } public static void main(String[] args) { PriorityQueue queue = new PriorityQueue(10, new Comparator<Viper>() { @Override public int compare(Viper v1, Viper v2) { // 设置优先级规则(倒序,等级越高权限越大) return v2.getLevel() - v1.getLevel(); } }); // 构建实体类 Viper v1 = new Viper(1, "Java", 1); Viper v2 = new Viper(2, "MySQL", 5); Viper v3 = new Viper(3, "Redis", 3); // 入列 queue.offer(v1); queue.offer(v2); queue.offer(v3); while (!queue.isEmpty()) { // 遍历名称 Viper item = (Viper) queue.poll(); System.out.println("Name:" + item.getName() + " Level:" + item.getLevel()); } } }以上代码的执行结果如下:
Name:MySQL Level:5
Name:Redis Level:3
Name:Java Level:1
从上述结果可以看出,优先队列的出队是不考虑入队顺序的,它始终遵循的是优先级高的元素先出队。
4.延迟队列延迟队列(DelayQueue)是基于优先队列 PriorityQueue 实现的,它可以看作是一种以时间为度量单位的优先的队列,当入队的元素到达指定的延迟时间之后方可出队。
我们来演示一下延迟队列的使用:
import lombok.Getter; import lombok.Setter; import java.text.DateFormat; import java.util.Date; import java.util.concurrent.DelayQueue; import java.util.concurrent.Delayed; import java.util.concurrent.TimeUnit; public class CustomDelayQueue { // 延迟消息队列 private static DelayQueue delayQueue = new DelayQueue(); public static void main(String[] args) throws InterruptedException { producer(); // 调用生产者 consumer(); // 调用消费者 } // 生产者 public static void producer() { // 添加消息 delayQueue.put(new MyDelay(1000, "消息1")); delayQueue.put(new MyDelay(3000, "消息2")); } // 消费者 public static void consumer() throws InterruptedException { System.out.println("开始执行时间:" + DateFormat.getDateTimeInstance().format(new Date())); while (!delayQueue.isEmpty()) { System.out.println(delayQueue.take()); } System.out.println("结束执行时间:" + DateFormat.getDateTimeInstance().format(new Date())); } static class MyDelay implements Delayed { // 延迟截止时间(单位:毫秒) long delayTime = System.currentTimeMillis(); // 借助 lombok 实现 @Getter @Setter private String msg; /** * 初始化 * @param delayTime 设置延迟执行时间 * @param msg 执行的消息 */ public MyDelay(long delayTime, String msg) { this.delayTime = (this.delayTime + delayTime); this.msg = msg; } // 获取剩余时间 @Override public long getDelay(TimeUnit unit) { return unit.convert(delayTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS); } // 队列里元素的排序依据 @Override public int compareTo(Delayed o) { if (this.getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) { return 1; } else if (this.getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) { return -1; } else { return 0; } } @Override public String toString() { return this.msg; } } }以上代码的执行结果如下:
开始执行时间:2020-10-20 20:17:28
消息1
消息2
结束执行时间:2020-10-20 20:17:31
从上述结束执行时间和开始执行时间可以看出,消息 1 和消息 2 都正常实现了延迟执行的功能。
5.其他队列