当前位置: 首页 > news >正文

java 常用并发队列- DelayQueue

1. 什么是 DelayQueue

DelayQueue 是一个支持 延迟获取元素 的阻塞队列,它的元素必须实现 java.util.concurrent.Delayed 接口,该接口要求元素定义一个 getDelay(TimeUnit unit) 方法,用来指定元素何时可以从队列中取出。DelayQueue 的内部是基于 优先级队列(PriorityQueue) 实现的,因此队列中的元素是按照延迟时间的长短来排序的,延迟时间最短的元素排在队头。

特点:
  • 无界队列DelayQueue 是一个无界阻塞队列,容量只受限于内存大小。
  • 线程安全DelayQueue 是线程安全的,可以在多线程环境下使用。
  • 元素按延迟时间排序:只有当元素的延迟期满时,它才可以被获取。
  • 实现 Delayed 接口:所有存入 DelayQueue 的元素都必须实现 Delayed 接口,该接口要求实现 getDelay(TimeUnit unit) 方法,以返回元素的剩余延迟时间。

2. DelayQueue 的实现原理

DelayQueue 是基于 优先级队列(PriorityQueue) 实现的。它的工作原理如下:

  1. 存储元素DelayQueue 采用 PriorityQueue 作为其内部数据结构,PriorityQueue 是一个基于堆(heap)的数据结构。DelayQueue 会根据元素的延迟时间对其进行排序,延迟时间最短的元素排在队头。

  2. 延迟处理:当从 DelayQueue 中获取元素时,如果队头元素的延迟时间还没有到达,则 take() 方法会阻塞,直到元素的延迟时间到达。如果使用 poll() 方法获取元素,则会立即返回 null,而不会阻塞。

  3. 线程安全DelayQueue 使用了内部锁来保证并发环境下的线程安全。

3. Delayed 接口

Delayed 接口是 DelayQueue 中元素必须实现的接口,它继承自 Comparable 接口,因此元素的延迟时间可以比较大小。Delayed 接口的核心方法是:

  • getDelay(TimeUnit unit):返回元素相对于当前时间的剩余延迟时间。TimeUnit 是一个时间单位枚举(如 SECONDSMILLISECONDS 等)。

  • compareTo(Delayed o):比较两个元素的延迟时间,用于排序。

4. DelayQueue 的常用方法

DelayQueue 继承了 BlockingQueue 接口的所有方法,以下是一些常用方法:

  • boolean offer(E e):将指定的元素插入队列中。
  • E take():从队列中获取并移除延迟时间到期的元素,如果没有到期的元素,线程会被阻塞直到有元素到期。
  • E poll():尝试获取并移除延迟时间到期的元素,如果没有到期的元素则返回 null
  • int size():返回队列中的元素数量。

5. 使用 DelayQueue 的示例

下面是一个使用 DelayQueue 实现延时任务调度的示例。我们创建了一个实现 Delayed 接口的任务类 DelayedTask,并将其放入 DelayQueue 中。然后,使用一个消费者线程不断从队列中获取到期的任务并执行它们。

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;// 定义一个实现 Delayed 接口的任务类
class DelayedTask implements Delayed {private final String name;     // 任务名称private final long delayTime;  // 延迟时间(纳秒)private final long expireTime; // 任务到期时间(纳秒)public DelayedTask(String name, long delayTime, TimeUnit unit) {this.name = name;this.delayTime = TimeUnit.NANOSECONDS.convert(delayTime, unit);  // 转换为纳秒this.expireTime = System.nanoTime() + this.delayTime;            // 计算到期时间}// 获取任务的剩余延迟时间@Overridepublic long getDelay(TimeUnit unit) {long remainingDelay = expireTime - System.nanoTime();  // 计算剩余延迟时间return unit.convert(remainingDelay, TimeUnit.NANOSECONDS); // 转换为指定单位}// 比较两个任务的延迟时间@Overridepublic int compareTo(Delayed other) {if (this.getDelay(TimeUnit.NANOSECONDS) < other.getDelay(TimeUnit.NANOSECONDS)) {return -1;}if (this.getDelay(TimeUnit.NANOSECONDS) > other.getDelay(TimeUnit.NANOSECONDS)) {return 1;}return 0;}// 任务执行的方法public void execute() {System.out.println("执行任务: " + name);}@Overridepublic String toString() {return "任务[" + name + "], 延迟时间: " + delayTime / 1_000_000 + " ms";}
}public class DelayQueueExample {public static void main(String[] args) {// 创建一个 DelayQueueBlockingQueue<DelayedTask> delayQueue = new DelayQueue<>();// 添加任务到 DelayQueuedelayQueue.offer(new DelayedTask("任务1", 3, TimeUnit.SECONDS));delayQueue.offer(new DelayedTask("任务2", 1, TimeUnit.SECONDS));delayQueue.offer(new DelayedTask("任务3", 5, TimeUnit.SECONDS));// 启动一个线程不断从 DelayQueue 中取出到期任务并执行new Thread(() -> {while (true) {try {DelayedTask task = delayQueue.take();  // 阻塞等待任务到期task.execute();  // 执行任务} catch (InterruptedException e) {e.printStackTrace();}}}).start();}
}
示例分析
  1. DelayedTask

    • DelayedTask 实现了 Delayed 接口,并定义了任务的名称、延迟时间和到期时间。
    • getDelay() 方法计算任务的剩余延迟时间,用于 DelayQueue 确定任务的到期顺序。
    • compareTo() 方法用于比较两个任务的延迟时间,以确保任务按到期时间排序。
  2. DelayQueue 使用

    • DelayQueue<DelayedTask> 用于存储 DelayedTask 对象。任务被插入队列时,会根据其延迟时间排序。
    • 消费者线程不断调用 take() 方法,从队列中获取到期任务并执行。由于 take() 是阻塞方法,如果没有到期的任务,会自动等待。
  3. 任务执行顺序

    • 在示例中,任务2 的延迟时间为 1 秒,因此会先被执行。接着是 任务1(3 秒)和 任务3(5 秒)。

6. DelayQueue 的应用场景

DelayQueue 主要应用于需要延时处理的场景,例如:

  1. 任务调度系统:在某些任务调度系统中,需要延时执行某些任务,DelayQueue 是实现延时任务调度的一个很好的选择。

  2. 缓存失效:在缓存系统中,可以使用 DelayQueue 来管理缓存失效时间,当缓存到期时自动删除或更新缓存。

  3. 连接超时处理:在网络编程中,可能需要对连接进行超时处理,当连接超过指定时间后自动关闭。

  4. 订单过期处理:在电子商务系统中,可能需要对订单进行延迟支付处理,如果在规定时间内未支付,则自动取消订单。

7. DelayQueue 的优缺点

优点
  1. 线程安全DelayQueue 是线程安全的,支持多个生产者和消费者线程的并发操作。
  2. 按延迟时间排序:队列中的元素按延迟时间排序,非常适合实现延时任务调度。
  3. 支持无界DelayQueue 是无界的,不需要担心队列溢出的问题。
缺点
  1. 内存消耗DelayQueue 是无界的,如果没有适当的管理,可能会导致内存消耗过多。
  2. **实时性要求

高的场景不适用**:DelayQueue 是基于延时操作的,如果需要实时性很强的操作,可能不适用。

8. 总结

DelayQueue 是 Java 并发库中非常有用的一种队列,特别适合用于延时任务调度、超时处理等场景。它通过 Delayed 接口和优先级队列的结合,实现了对元素的延时处理和有序管理。
DelayQueue 是 Java 并发包 (java.util.concurrent) 中提供的一种 无界阻塞队列,用于存放实现了 Delayed 接口的元素,这些元素只有在其延迟期满时才能被从队列中获取。DelayQueue 通常用于实现延时任务调度、任务超时处理等场景。

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 靶场战神为何会陨落?
  • IP地址查询功能详解—构建风险画像与代理识别
  • Type-C接口 未来发展趋势
  • 重拾英语,从头学起
  • 牛客std:pair,指针+递归+整体法的使用
  • 红黑树的插入 C++
  • tomcat架构设计分析,核心组件详解
  • 【C++】容器list常用接口详解
  • idea新建父工程和添加导入新模块的步骤
  • 关于STM32运行时卡住问题
  • Adobe DC 2022提示无法识别的错误 - 解决方案
  • C4 单细胞测序中,oligo文库 和 cDNA 文库 各自的功能和区别
  • 【Kubernetes知识点问答题】Service 发现
  • TPM在解决哪些类型的问题时最有效?
  • log4j 清除MDC上下文 MDC分类日志
  • JS中 map, filter, some, every, forEach, for in, for of 用法总结
  • 【笔记】你不知道的JS读书笔记——Promise
  • 2017年终总结、随想
  • Git的一些常用操作
  • Java到底能干嘛?
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • mac修复ab及siege安装
  • Redash本地开发环境搭建
  • spring cloud gateway 源码解析(4)跨域问题处理
  • Terraform入门 - 1. 安装Terraform
  • Zsh 开发指南(第十四篇 文件读写)
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 第十八天-企业应用架构模式-基本模式
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 爬虫模拟登陆 SegmentFault
  • 正则表达式
  • 策略 : 一文教你成为人工智能(AI)领域专家
  • 说说我为什么看好Spring Cloud Alibaba
  • 整理一些计算机基础知识!
  • ‌JavaScript 数据类型转换
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #vue3 实现前端下载excel文件模板功能
  • ${ }的特别功能
  • $var=htmlencode(“‘);alert(‘2“); 的个人理解
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (4.10~4.16)
  • (7)摄像机和云台
  • (el-Transfer)操作(不使用 ts):Element-plus 中 Select 组件动态设置 options 值需求的解决过程
  • (SERIES12)DM性能优化
  • (补充)IDEA项目结构
  • (初研) Sentence-embedding fine-tune notebook
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (第三期)书生大模型实战营——InternVL(冷笑话大师)部署微调实践
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (附源码)spring boot北京冬奥会志愿者报名系统 毕业设计 150947
  • (理论篇)httpmoudle和httphandler一览
  • (六)Hibernate的二级缓存
  • (南京观海微电子)——COF介绍
  • (七)c52学习之旅-中断