Java中的5大队列,你知道几个? (3)

优先队列是根据二叉堆实现的,二叉堆的数据结构如下图所示:

image.png


二叉堆分为两种类型:一种是最大堆一种是最小堆。以上展示的是最大堆,在最大堆中,任意一个父节点的值都大于等于它左右子节点的值。

因为优先队列是基于二叉堆实现的,因此它可以将优先级最好的元素先出队。

接下来我们来演示一下优先队列的使用:

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 实现的,它可以看作是一种以时间为度量单位的优先的队列,当入队的元素到达指定的延迟时间之后方可出队。

image.png

我们来演示一下延迟队列的使用:

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.其他队列

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsspdw.html