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 通常用于实现延时任务调度、任务超时处理等场景。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/51966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python简易IDE工作界面制作

、 休闲一下&#xff0c;学习编程还是要学习一些界面编程&#xff0c;能够根据需要制作图形操作界面&#xff0c;这样我们开发的程序才能方便操作和使用&#xff0c;同时获得更友好的人机交互体验。下面是一个用PyQt5制作的简易界面&#xff0c;供大学参考。如下图所示&a…

【淘宝采集项目经验分享】商品评论采集 |商品详情采集 |关键词搜索商品信息采集

商品评论采集 1、输入商品ID 2、筛选要抓取评论类型 3、填写要抓取的页数 4、立刻提交-启动测试 5、等爬虫结束后就可以到“爬取结果”里面下载数据 商品详情采集 1、输入商品ID 2、立刻提交-启动爬虫 3、等爬虫结束后就可以到“爬取结果”里面下载数据 taobao.item_…

【Python】Python 读取Excel、DataFrame对比并选出差异数据,重新写入Excel

背景&#xff1a;我在2个系统下载出了两个Excel&#xff0c;现在通过对下载的2个Excel数据&#xff0c;并选出差异数据 从新写入一个新的Excel中 differences_url rC:\Users\LENOVO\Downloads\differences.xlsx; //要生成的差异Excel的位置及名称 df1_url rC:\Users\LENOVO\Dow…

【 WPF 中常用的Brush类的简要介绍、使用方法和适用场景】

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 WPF 中常用的 Brush 类的简要介绍、使用方法和适用场景 使用场景解释示例代码&#xff08;为按钮创建一个线性渐变背景&#xff09; Brush 类描述使用示例适用场景SolidColor…

cocotb备忘录

按位给和int int后接的值&#xff0c;建议在32之内。大于32位建议按位给&#xff0c;因为int强制类型转换有范围 第二&#xff0c;低位给到低位&#xff0c;高位给到高位 # 将src_ip和dst_ip给到phv中,TMD以后只要报错在这个范围里面&#xff0c;TMD直接马上用手算一遍能不能…

0903,LIST(merge,splice,sort,unique),SET(insert,erase)

目录 03_vector_delete.cc 04_vector_shrink.cc 05_vec_emplace_back.cc 06_listspec_splice.cc 07_classstruct.cc 08_set.cc 09_setErase.cc 作业 01 STL中的容器包括哪些&#xff1f;各自具有哪些特点&#xff1f; 02 题目&#xff1a;编写代码&#xff1a;将…

Docker设置socks5代理

查看测试环境 $ lsb_release -a No LSB modules are available. Distributor ID: Ubuntu Description: Ubuntu 22.04.4 LTS Release: 22.04 Codename: jammy修改 Docker 服务代理配置文件 $ sudo mkdir -p /etc/systemd/system/docker.service.d $ sudo vi /etc/systemd/syst…

使用Spring Boot拦截器实现时间戳校验以防止接口被恶意刷

使用Spring Boot拦截器实现时间戳校验以防止接口被恶意刷 在开发Web应用程序时&#xff0c;接口被恶意刷请求&#xff08;例如DDoS攻击或暴力破解&#xff09;是一个常见的安全问题。为了提高接口的安全性&#xff0c;我们可以在服务端实现时间戳校验&#xff0c;以确保请求的…

基于Spring的消息推送实战(Websocket和前端轮询实现)

基于Spring的消息推送实战&#xff08;Websocket和前端轮询实现&#xff09; 本文介绍了基于Spring的消息推送实现方法&#xff0c;主要介绍了websocket实时消息推送方法&#xff08;ServerEndpoint方式实现&#xff09;&#xff0c;以及前端客户端轮询方式的消息推送。 一、消…

【Qt】 QComboBox | QSpinBox

文章目录 QComboBox —— 下拉框QComboBox 属性核心方法核心信号QComboBox 使用 QSpinBox —— 微调框QSpinBox 属性核心信号QSpinBox 使用 QComboBox —— 下拉框 QComboBox 属性 QComboBox —— 表示下拉框 currentText ——当前选中的文本 currentindex ——当前选中的条…

如何在虚拟机中安装部署K8S?

教程参考&#xff1a;centos7安装k8s 1.28版本&#xff0c;基于科学-CSDN博客 环境准备&#xff1a; 准备三台机器&#xff0c;都做以下操作&#xff0c;或者只准备一个机器&#xff0c;最后再克隆两台。 yum&#xff1a; 换源&#xff0c;这是阿里云的源 sudo wget -O /etc…

详解Asp.Net Core管道模型中的五种过滤器的适用场景与用法

1. 前言 在 ASP.NET Core 中&#xff0c;过滤器是一种用于对请求管道进行前置或后置处理的组件。它们可以在请求处理的不同阶段干预和修改请求和响应&#xff0c;以实现一些通用的处理逻辑或功能增强。 ASP.NET Core 的管道模型由多个中间件组成&#xff0c;而过滤器是这个模…

kafka及异步通知文章上下架

1)自媒体文章上下架 需求分析 2)kafka概述 消息中间件对比 特 性 ActiveMQ RabbitMQ RocketMQ Kafka 开 发 语 言 java erlang java scala 单 机 吞 吐 量 万级 万级 10万级 100万级 时 效 性 ms us ms ms级以内 可 用 性 高&#xff08;主从&#xff0…

如何从 Bak 文件中恢复 SQL数据库?(3种方法)

如何从 .bak 文件恢复 SQL数据库&#xff1f; 在数据库管理和维护过程中&#xff0c;数据的安全性和完整性至关重要。备份文件&#xff08;.bak 文件&#xff09;是 SQL Server 中常用的数据库备份格式&#xff0c;它包含了数据库的完整副本&#xff0c;用于在数据丢失、系统故…

flutter与原生怎么交互的

Flutter 与原生平台(如 Android 和 iOS)之间的交互可以通过**平台通道(Platform Channels)**实现。这允许你在 Flutter 应用中调用原生代码,或者从原生代码中调用 Flutter 代码。这种机制使得你可以利用原生平台提供的特性和 API,同时保持大部分应用代码在 Flutter 中。 …

4. 第一个3D案例—创建3D场景

入门Three.js的第一步&#xff0c;就是认识场景Scene、相机Camera、渲染器Renderer三个基本概念&#xff0c;接下来&#xff0c;咱们通过三小节课&#xff0c;大家演示“第一个3D案例”完成实现过程。 学习建议&#xff1a;只要你能把第一个3D案例搞明白&#xff0c;后面学习就…

二百六十、Java——采集Kafka数据,解析成一条条数据,写入另一Kafka中(复杂JSON)

一、目的 由于部分数据类型频率为1s&#xff0c;从而数据规模特别大&#xff0c;因此完整的JSON放在Hive中解析起来&#xff0c;尤其是在单机环境下&#xff0c;效率特别慢&#xff0c;无法满足业务需求。 而Flume的拦截器并不能很好的转换数据&#xff0c;因为只能采用Java方…

SEO之网站结构优化(十四-内部链接及权重分配3)

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议 2、“新手上云”能够为你开启探索云世界的第一步 博客&#xff1a;阿幸SEO~探索搜索排名之道 7、锚文字分布及变化 前面…

新手c语言讲解及题目分享(十四)--函数专项练习(一)

目录 前言 一.函数的定义 1.函数定义包括的内容&#xff1a; Ⅰ.指定函数类别 Ⅱ.指定函数类型 Ⅲ.指定函数名 Ⅳ.指定函数的参数名称和类型 Ⅴ.指定函数的函数体 2.函数定义的一般形式&#xff1a; Ⅰ.有参函数的定义形式&#xff1a; Ⅱ.无参函数的定义形式&#x…

C语言从头学55——学习头文件errno.h、float.h

1、头文件 errno.h 中的变量 errno 的使用 在 errno.h 定义了一个 int 类型的变量 errno&#xff08;错误码&#xff09;&#xff0c;如果发现这个变量出现非零值&#xff0c;表示已经执行的函数发生了错误。这个变量一般多用于检查数学函数运算过程中发生的错误。 …