【当年笔记】集合之Queue队列
1)Queue 分类
- 双端队列:双端队列(Deque)是 Queue 的子类也是 Queue 的补充类,头部和尾部都支持元素插入和获取。
- 阻塞队列:阻塞队列指的是指添加或删除元素时,如果没有成功,会阻塞并挂起等待,直到操作执行完成。
- 非阻塞队列:非阻塞队列指的是指添加或删除元素时,如果没有成功,会直接返回操作的结果。双端队列也属于非阻塞队列。
阻塞队列
1)BlockingQueue
常用方法
插入元素:
- add(E):添加元素到队尾,成功返回 true,失败抛出异常;
- offer(E):添加元素到队尾,成功返回 true,失败返回 false ;
- offer(E o,Long timeOut,Timme):添加元素到队尾,成功返回 true,失败返回 false ;
- put(E):添加元素到队尾,如果该队列已满,则一直阻塞。
移除元素: - remove(Object):移除指定元素,成功返回 true,失败返回 false;
- poll(): 获取并移除队列的首个元素,如果队列为空,则返回 null;
- take():获取并移除队列首个元素,如果队列尾空,则一直阻塞。
查看元素: - peek():获取但不移除队列的首个元素,若队列为空,则返回 null。
2)ArrayBlockingQueue
是一个有边界的阻塞队列,它的内部实现是一个数组。它的容量是有限的,我们必须在其初始化的时候指定它的容量大小,容量大小一旦指定就不可改变。
ArrayBlockingQueue 不允许元素为 null
这个类新增offer(E e, long timeout, TimeUnit unit)方法:添加失败后会等待一段时间,超时后返回false。
3)LinkedBlockingQueue
是一个由链表实现的有界阻塞队列,容量默认值为Integer.MAX_VALUE,也可以自定义容量,建议指定容量大小,默认大小在添加速度大于删除速度情况下有造成内存溢出的风险
4)DelayQueue
DelayQueue 是一个支持延时获取元素的无界阻塞队列,队列中的元素必须实现 Delayed接口,在创建元素时可以指定延迟时间,只有到达了延迟的时间之后,才能获取到该元素。
非阻塞队列
ConcurrentLinkedQueue是一个基于链接节点的无界线程安全队列。
优先级队列
PriorityQueue 一个基于优先级堆的无界优先级队列。可根据构造队列时提供的 Comparator排序,该队列不许有null。
- PriorityQueue 是非线程安全的,在多线程情况下可使用 PriorityBlockingQueue 类替代
1.ArrayBlockingQueue 和 LinkedBlockingQueue 的区别是什么?
ArrayBlockingQueue 和 LinkedBlockingQueue 都实现自阻塞队列
BlockingQueue,它们的区别主要体现在以下几个方面:
- ArrayBlockingQueue 使用时必须指定容量值,LinkedBlockingQueue 可以不用指定;
- ArrayBlockingQueue 的最大容量值是使用时指定的,并且指定之后就不允许修改;而 LinkedBlockingQueue 最大的容量为 Integer.MAX_VALUE;
- ArrayBlockingQueue 数据存储容器是采用数组存储的;而 LinkedBlockingQueue 采用的是 Node 节点存储的。
2.Java 中常见的阻塞队列有哪些?
答:Java 中常见的阻塞队列如下:
- ArrayBlockingQueue,由数组结构组成的有界阻塞队列;
- PriorityBlockingQueue,支持优先级排序的无界阻塞队列;
- SynchronousQueue,是一个不存储元素的阻塞队列,会直接将任务交给消费者,必须等队列中的添加元素被消费后才能继续添加新的元素;
- LinkedBlockingQueue,由链表结构组成的阻塞队列;
- DelayQueue,支持延时获取元素的无界阻塞队列
3.如何手动实现一个延迟消息队列?
可以用DelayQueue延迟队列来解决这个问题。实现思路,消息队列分为生产者和消费者,生产者用于增加消息,消费者用于获取并消费消息,我们只需要生产者把消息放入到DelayQueue 队列并设置延迟时间,消费者循环使用 take() 阻塞获取消息即可。完整的实现代码如下:
public class CustomDelayQueue {
// 消息编号
static AtomicInteger MESSAGENO = new AtomicInteger(1);
public static void main(String[] args) throws InterruptedException {
DelayQueue<DelayedElement> delayQueue = new DelayQueue<>();
// 生产者1
producer(delayQueue, "生产者1");
// 生产者2
producer(delayQueue, "生产者2");
// 消费者
consumer(delayQueue);
}
//生产者
private static void producer(DelayQueue<DelayedElement> delayQueue, String name) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
// 产生 1~5 秒的随机数
long time = 1000L * (new Random().nextInt(5) + 1);
try {
Thread.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 组合消息体
String message = String.format("%s,消息编号:%s 发送时间:%s 延迟:%s 秒",
name, MESSAGENO.getAndIncrement(), DateFormat.getDateTimeInstance().format(new Date()), time / 1000);
// 生产消息
delayQueue.put(new DelayedElement(message, time));
}
}
}).start();
}
//消费者
private static void consumer(DelayQueue<DelayedElement> delayQueue) {
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
DelayedElement element = null;
try {
// 消费消息
element = delayQueue.take();
System.out.println(element);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
// 延迟队列对象
static class DelayedElement implements Delayed {
// 过期时间(单位:毫秒)
long time = System.currentTimeMillis();
// 消息体
String message;
// 参数:delayTime 延迟时间(单位毫秒)
public DelayedElement(String message, long delayTime) {
this.time += delayTime;
this.message = message;
}
@Override
// 获取过期时间
public long getDelay(TimeUnit unit) {
return unit.convert(time - 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 message + " |执行时间:" + DateFormat.getDateTimeInstance().format(new Date());
}
}
}
以上程序支持多生产者,执行的结果如下:
> 生产者1,消息编号:1 发送时间:2019-6-12 20:38:37 延迟:2 秒 |执行时间:2019-6-12 20:38:39
>
> 生产者2,消息编号:2 发送时间:2019-6-12 20:38:37 延迟:2 秒 |执行时间:2019-6-12 20:38:39
>
> 生产者1,消息编号:3 发送时间:2019-6-12 20:38:41 延迟:4 秒 |执行时间:2019-6-12 20:38:45
>
> 生产者1,消息编号:5 发送时间:2019-6-12 20:38:43 延迟:2 秒 |执行时间:2019-6-12 20:38:45
【当年笔记】集合之Queue队列的更多相关文章
- C#部分---特殊集合:stack栈集合、queue队列集合、哈希表集合。
1.stack栈集合:又名 干草堆集合 栈集合 特点:(1)一个一个赋值 一个一个取值(2)先进后出实例化 初始化 Stack st = new Stack(); //添加元素用push st.Pus ...
- Scala学习笔记--集合类型Queue,Set
补充知识:http://www.importnew.com/4543.html 正文开始 scala.collection.immutable scala.collection.mutable 队列Q ...
- Stack集合 Queue队列集合 Hashtable哈希表
Stack集合 干草堆集合 栈集合 栈;stack,先进后出,一个一个赋值,一个一个取值,安装顺序来. 属性和方法 实例化 初始化 Stack st = new Stack(); 添加元素 个数 Co ...
- MSMQ学习笔记二——创建Message Queue队列
一.创建Message Queue队列的主要流程 1.定义MQQUEUEPROPS 结构: 2.设置消息队列属性: 3.初始化MQQUEUEPROPS 结构: 4.调用MQCreateQueue创建队 ...
- 特殊集合 Stack Queue Hashtable
//Stack 干草堆集合 栈集合 先进后出 Stack st = new Stack(); //实例化 初始化 st.Push(2); //添加元素 st.Push(6); s ...
- JavaSE笔记-集合
Java集合大致可分为:List,Set,Map,Queue List:有序,可重复 Set:无序(输出和插入顺序不一定一致),不可重复 Map:映射关系,根据key去访问value Queue:队列 ...
- 进击的Python【第九章】:paramiko模块、线程与进程、各种线程锁、queue队列、生产者消费者模型
一.paramiko模块 他是什么东西? paramiko模块是用python语言写的一个模块,遵循SSH2协议,支持以加密和认证的方式,进行远程服务器的连接. 先来个实例: import param ...
- Java Queue队列
前言 Queue队列是一种特殊的线性表,它只允许在表的前端进行删除操作,而在表的后端进行插入操作,LinkedList类实现了Queue接口,因此我们可以把LinkedList当成Queue来用. ...
- C#基础---Queue(队列)的应用
Queue队列,特性先进先出. 在一些项目中我们会遇到对一些数据的Check,如果数据不符合条件将会把不通过的信息返回到界面.但是对于有的数据可能会Check很多条件,如果一个数据一旦很多条件不 ...
- 第19章 queue队列容器
/* 第19章 queue队列容器 19.1 queue技术原理 19.2 queue应用基础 19.3 本章小结 */ // 第19章 queue队列容器 // 19.1 queue技术原理 // ...
随机推荐
- JZOJ 3304. Theresa与数据结构
\(\text{Problem}\) 标准四维偏序 带修改(加和删除)和询问的三维空间正方体内部(包括边上)的点的数目 \(\text{Analysis}\) 打法很多,\(\text{cdq}\) ...
- 钓鱼攻击之:Flash 网页钓鱼
钓鱼攻击之:Flash 网页钓鱼 目录 钓鱼攻击之:Flash 网页钓鱼 1 准备资料 2 具体钓鱼流程 3 生成后门并捆绑flash的安装程序 4 处理WEB站点过程 1 准备资料 Flash网站克 ...
- OpenSCAD:一款用于创建实体3D CAD对象的软件
推荐:使用 NSDT场景设计器 快速搭建 3D场景. 原文链接:https://www.mvrlink.com/openscad/ OpenSCAD是一个用于创建实体3D CAD对象的软件.它是免费软 ...
- LeetCode-780 到达终点
来源:力扣(LeetCode)链接:https://leetcode-cn.com/problems/reaching-points 题目描述 给定四个整数 sx , sy ,tx 和 ty,如果通过 ...
- Linux的终端(base),进入base环境
正常界面,如下 带有(base) 一般是由于安装了conda环境管理软件,它自带一个base环境.第一次安装时出现这种情况可能是由于软件将启动base环境的命令写入-/.bashrc 文件,这就相当于 ...
- grafana嵌入iframe,websoket连接报错400或403(nginx代理)
1.custom.ini配置文件修改allowed_origins=* 2. nginx中增加配置,如下:
- flannel 关闭SNAT
flannel 关闭SNAT 默认情况下,flannel 访问集群外网络是通过 SNAT 成宿主机 ip 方式,在一些金融客户环境中为了能实现防火墙规则,需要直接针对 POD ip 进行进行规则配置, ...
- leetcode刷题(三)
1.图论 找到小镇的法官 在一个小镇里,按从 1 到 N 标记了 N 个人.传言称,这些人中有一个是小镇上的秘密法官. 如果小镇的法官真的存在,那么: 小镇的法官不相信任何人.每个人(除了小镇法官外) ...
- list变成String类型
list变成String类型 CollectionUtils.isEmpty(vo.getImgs())?"" : String.join(";", (Stri ...
- 数值分析之数值积分 4.X
求积公式 \[\int_{a}^{b} f(x) \mathrm{d} x \approx \sum_{k=0}^{n} A_{k} f\left(x_{k}\right) \] \(A_k\) 为求 ...