mq - 优先队列PriorityQueue
场景描述
队列通常采用 FIFO(先进先出) 策略,可以满足多数情况下的开发需求,但是也有其不足之处。
例如:
我要小明帮我买早餐,
第一次,“小明,你后天帮我买牛奶吧!”,
过了一会儿,“小明,你明天帮我买豆浆呗!”。
这个案例中,我先叫小明买的牛奶,再叫他买的豆浆,如果按照普通队列,按顺序执行,先买牛奶显然是错的。
优先队列
优先队列满足了上述的开发需求,队列中的元素按照自然顺序(Comparator)进行排序,通过Comparable接口可以定制任意的优先策略。
常见的优先队列有:
- PriorityQueue
优先队列 - PriorityBlockingQueue
阻塞优先队列(线程安全的队列) - DelayQueue
延迟队列(函数使用了可重入锁,是线程安全的队列),延迟队列所有元素必须继承Delayed接口,Delayed接口又继承自Comparable接口,专门用于时间的比较。
这三者优先队列之间不存在继承关系,DelayQueue内部包含PriorityQueue实例,是一个优先队列的装饰者;PriorityBlockingQueue源码也不同与另外两个。
扩展
在高级的队列中(比如 activemq),也是有类似的功能,如果有业务需求,可以调整配置启用功能。
案例
复用上一个文章的工具类,通过PriorityBlockingQueue实现上述中买早餐的案例,顺便展示Delayed接口的使用方法。
package com.sea.common.util;
import java.util.concurrent.Delayed;
import java.util.concurrent.PriorityBlockingQueue;
import java.util.concurrent.TimeUnit;
class DelayItem implements Delayed {
private long milli;
private String msg;
@Override
public String toString() {
return msg;
}
public DelayItem(long milli, String msg) {
this.milli = milli;
this.msg = msg;
}
@Override
public long getDelay(TimeUnit unit) {
/**
* TimeUnit提供了时间转换的算法,如果确定了延迟的精度,直接return milli即可
*/
return unit.convert(milli, TimeUnit.MILLISECONDS);
}
@Override
public int compareTo(Delayed o) {
return this.milli == o.getDelay(TimeUnit.NANOSECONDS) ? 0
: (this.milli > o.getDelay(TimeUnit.NANOSECONDS) ? 1 : -1);
}
}
public class Test {
public static void main(String[] args) throws InterruptedException {
Handler<DelayItem> handler = new Handler<DelayItem>() {
@Override
public void handleMessage(DelayItem msg) throws Exception {
Thread.sleep(1000);
System.out.println(msg);
}
};
BlockingLopper<DelayItem> lopper = new BlockingLopper<DelayItem>();
lopper.setDummy(new DelayItem(Long.MAX_VALUE, ""));
lopper.setHandler(handler);
lopper.setQueue(new PriorityBlockingQueue<>(2));
lopper.loop();
lopper.offer(new DelayItem(200, "小明,你后天帮我买牛奶吧!"));
lopper.offer(new DelayItem(100, "小明,你明天帮我买豆浆呗!"));
System.out.println("--------------------");
lopper.stopLoop();
}
}
内容补充
在java-api中还有几个比较抢眼的名词,因为不是十分常用,这里简单介绍。
ConcurrentLinkedQueue同步线性队列,一个基于链接节点的无界线程安全队列。此队列按照 FIFO(先进先出)原则对元素进行排序。针对线程安全问题,java.util.concurrent 包下实现了多个线程安全的Collection和Map,名字以Concurrent开头,util包下有对应的非线程安全实现类,ConcurrentLinkedQueue与LinkedList功能相对应。
Deque
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY