Java DelayQueue 延迟队列

Java DelayQueue 延迟队列

1. DelayQueue 概述

DelayQueue 是 Java 并发包(java.util.concurrent)中的一个 无界 阻塞队列,用于存储实现了 Delayed 接口的元素。队列中的元素只有在达到指定的延迟时间后才能被获取。

2. DelayQueue 的底层数据结构

DelayQueue 的底层数据结构是 优先级队列(PriorityQueue),它是一个小顶堆(最小堆),根据元素的过期时间进行排序。

  • 底层采用 PriorityQueue(基于堆的实现)
  • 按照到期时间升序排列,即最早过期的元素在堆顶
  • 元素未过期时,take() 方法会阻塞
  • 支持多线程并发访问

3. DelayQueue 的实现原理

  • 元素需实现 Delayed 接口,重写 getDelay() 方法,返回剩余的延迟时间

  • DelayQueue 内部维护一个 PriorityQueue<Delayed>

  • 插入元素时,按照到期时间排序,最早到期的元素位于堆顶。

  • take()
    

    方法获取堆顶元素:

    • 若到期,直接返回该元素。
    • 若未到期,线程阻塞,直到该元素可用。
    • 使用锁 + 条件变量ReentrantLock + Condition)控制并发访问。

4. DelayQueue 的应用场景

DelayQueue 适用于 延迟执行、定时任务、缓存超时管理 等场景,包括:

  • 任务调度(如延迟执行任务、重试机制)
  • 定时消息队列(如 Kafka 里的延时消息)
  • 订单超时取消(未支付订单自动取消)
  • 缓存自动过期(定期清除缓存)
  • 连接超时管理(网络连接的超时处理)

5. DelayQueue 的优缺点

优点

  • 高效的时间管理,自动处理过期元素
  • 线程安全,内部使用 ReentrantLock 保证并发安全
  • 无界队列,但受内存限制
  • 阻塞机制,减少 CPU 轮询

缺点

  • 不支持元素移除(除非手动遍历 remove()
  • 不能提前获取未到期元素poll() 只返回到期元素)
  • 无上限(可能导致 OOM)

6. DelayQueue 的替代方案

需求替代方案
需要定时任务ScheduledThreadPoolExecutor
需要分布式延迟队列Redis ZSet(基于时间戳排序)
高吞吐延迟消息队列Kafka + 延迟插件
低延迟任务调度TimeWheel(时间轮算法,如 Netty 的 HashedWheelTimer)

7. DelayQueue 使用示例

(1) 定义延迟元素

import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;class DelayedTask implements Delayed {private final long delayTime; // 延迟时间private final long expireTime; // 过期时间private final String name;public DelayedTask(String name, long delay, TimeUnit unit) {this.name = name;this.delayTime = TimeUnit.MILLISECONDS.convert(delay, unit);this.expireTime = System.currentTimeMillis() + this.delayTime;}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));}@Overridepublic String toString() {return "Task{" + "name='" + name + '\'' + ", expireTime=" + expireTime + '}';}
}

(2) 使用 DelayQueue

import java.util.concurrent.DelayQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;public class DelayQueueExample {public static void main(String[] args) {DelayQueue<DelayedTask> queue = new DelayQueue<>();queue.add(new DelayedTask("Task1", 3, TimeUnit.SECONDS));queue.add(new DelayedTask("Task2", 1, TimeUnit.SECONDS));queue.add(new DelayedTask("Task3", 5, TimeUnit.SECONDS));ExecutorService executor = Executors.newSingleThreadExecutor();executor.submit(() -> {while (!queue.isEmpty()) {try {DelayedTask task = queue.take(); // 阻塞获取到期任务System.out.println("Executing: " + task);} catch (InterruptedException e) {Thread.currentThread().interrupt();}}});executor.shutdown();}
}

(3) 运行结果

Executing: Task{name='Task2', expireTime=...}  // 1s 后执行
Executing: Task{name='Task1', expireTime=...}  // 3s 后执行
Executing: Task{name='Task3', expireTime=...}  // 5s 后执行

8. 总结

  • DelayQueue 是基于优先级队列的小顶堆实现的阻塞队列
  • 元素需实现 Delayed 接口,getDelay() 返回剩余时间。
  • 适用于 延迟任务调度、缓存过期管理、订单超时 等场景。
  • 主要优点是 线程安全、自动延迟控制,缺点是 无法主动获取未到期元素
  • 可用 ScheduledThreadPoolExecutor、Redis ZSet、Kafka 延时队列 作为替代方案。

分布式微服务架构下,能使用DelayQueue吗?

分布式微服务架构 下,不推荐直接使用 DelayQueue,主要原因如下:

1. DelayQueue 的局限性

  • 单机限制DelayQueueJVM 内存队列,它运行在单个进程,无法在多个微服务实例间共享数据,不能保证高可用性和扩展性
  • 数据丢失风险:若微服务实例崩溃或重启,DelayQueue 中的任务会丢失,缺乏持久化机制。
  • 无水平扩展能力:随着流量增长,多个实例无法共享队列,容易成为瓶颈。

2. 适用于 DelayQueue 的场景

尽管 DelayQueue 不能直接用于分布式架构,但在单机任务调度、短时间小规模的延迟任务场景下仍然可行,例如:

  • 同一个微服务实例内的短期任务(如 1-10 秒级的延迟任务)
  • 不需要高可靠性的本地任务(如定期缓存清理)
  • 没有跨实例同步要求的任务(如本地事件延迟处理)

3. 分布式替代方案

若要在分布式微服务架构中实现可扩展、高可用的延迟任务调度,可以采用以下方案:

(1) Redis ZSet(有序集合)+ 定时轮询
  • 原理:利用 Redis 的 ZSet(有序集合),按照 score 存储任务的执行时间戳,每隔 N 毫秒 轮询一次取出到期任务执行。

  • 优势:

    • 支持 分布式部署,多个实例可共享数据
    • 持久化,即使服务重启,任务仍然存在
    • 高性能,Redis 读写性能优越
  • 示例:

    jedis.zadd("delayQueue", System.currentTimeMillis() + 5000, "order:123"); // 5s 后执行
    Set<String> tasks = jedis.zrangeByScore("delayQueue", 0, System.currentTimeMillis());
    if (!tasks.isEmpty()) {tasks.forEach(task -> {process(task); // 处理任务jedis.zrem("delayQueue", task); // 移除已处理任务});
    }
    
  • 适用场景:

    • 订单超时处理
    • 定时消息推送
    • 低吞吐的延迟任务(如秒级延迟)
(2) Kafka + 延迟队列插件
  • 原理:Kafka 通过 Kafka Streams延迟队列插件(如 Kafka Delay Message)支持延迟消费消息。
  • 适用场景:
    • 高吞吐的延迟任务
    • 可靠的分布式消息队列
  • 缺点:
    • 依赖 Kafka,适用于 需要消息队列的业务
(3) RabbitMQ/ActiveMQ TTL + 死信队列
  • 原理:RabbitMQ 支持 TTL(Time-To-Live) 设置,消息超时后自动进入 DLX(Dead Letter Exchange, 死信队列),可用 消费者监听 处理。

  • 适用场景:

    • 需要可靠消息队列
    • 需要高吞吐延迟任务
  • 示例:

    channel.queueDeclare("delayQueue", true, false, false, Map.of("x-message-ttl", 5000));
    channel.basicPublish("", "delayQueue", MessageProperties.PERSISTENT_TEXT_PLAIN, "Delayed Message".getBytes());
    
  • 缺点:

    • 依赖消息中间件,适用于 消息驱动的系统
(4) 分布式任务调度框架
  • 常见框架:
    • XXL-JOB(轻量级,适用于小规模定时任务)
    • Elastic-Job(基于 Zookeeper,适用于高并发调度)
    • Quartz + DB 持久化(适用于复杂定时任务)
  • 适用场景:
    • 定时任务执行
    • 任务分片调度
    • 可持久化任务队列

4. 结论

建议:如果是 单机应用,可以使用 DelayQueue;如果是 分布式微服务架构,建议使用 Redis ZSet / Kafka / RabbitMQ / 任务调度框架 实现延迟任务。

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

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

相关文章

LeetCode 解题思路 22(Hot 100)

解题思路&#xff1a; 递归思路&#xff1a; 传入当前节点的最小值和最大值&#xff0c;递归判断左右子树。结束条件&#xff1a; 当前节点为空或不满足二叉搜索树。 Java代码&#xff1a; class Solution {public boolean isValidBST(TreeNode root) {return isValidBST(ro…

乐享数科:政策助推假日经济,2月普惠金融-景气指数稳中有升

数据显示&#xff0c;2025年2月普惠金融-景气指数达48.99点&#xff0c;较1月上升0.03点。 企业运行持续向好&#xff0c;企业信心预期和经营活力回升。“假日经济”与“政策效应”相互叠加&#xff0c;市场供求格局有所改善&#xff0c;景气水平稳步恢复。 普惠金融-景气指数…

leetcode日记(108)验证回文串

看上去很简单&#xff0c;其实很麻烦。 一开始写的递归&#xff0c;但是内存超限……搜了下发现原因是每次递归调用都会创建一个新的字符串副本&#xff0c;这在处理长字符串时会占用大量内存。 class Solution { public:bool isPalindrome(string s) {if(s.size()0||s.size(…

用css绘制收银键盘

最近需求说需要自己弄个收银键盘&#xff0c;于是乎直接上手搓 主要基于Vue3写的&#xff0c;主要是CSS <template><view class"container"><view class"info"><image class"img" src"" mode"">&l…

智能车间管理系统(源码+文档+讲解+演示)

引言 在现代制造业中&#xff0c;智能车间管理系统正成为推动工业4.0和智能制造的关键力量。它通过整合先进的信息技术和自动化技术&#xff0c;优化生产流程&#xff0c;提高生产效率&#xff0c;降低成本&#xff0c;并确保产品质量。 系统概述 智能车间管理系统采用前后端…

Model Context Protocol - Prompts

1. 概述 Model Context Protocol (MCP) 提供了一种标准化的方式&#xff0c;使服务器能够向客户端暴露提示模板&#xff08;prompts&#xff09;。Prompts 是服务器提供的结构化消息和指令&#xff0c;用于与语言模型进行交互。客户端可以发现可用的提示、获取其内容&#xff…

办公自动化:使用 Python 生成 Word 文件:自动生成数据库文档 Word 文件

简简单单 Online zuozuo :本心、输入输出、结果 文章目录 办公自动化:使用 Python 生成 Word 文件:自动生成数据库文档 Word 文件前言一、环境准备二、编写代码三、编写 Word 模版文件接收数据四、运行代码,生成文件,大功告成五、说明办公自动化:使用 Python 生成 Word 文…

嵌入式GPRS协议面试题及参考答案

目录 GPRS 的全称是什么?简述其核心设计目标。 GPRS 中 DNS 服务器的核心作用是什么? BTS 在 EDGE 升级时需要哪些硬件调整? GPRS 的时隙分配策略如何影响多用户并发? 解释 PDCH(分组数据信道)的动态分配机制。 如何判断天馈接反或鸳鸯线问题? GPRS 的 RLC/MAC 层…

Docker 内部通信(网络)

1. 创建自定义桥接网络 首先&#xff0c;创建一个自定义的Docker网络。这可以通过docker network create命令完成。例如&#xff0c;我们可以创建一个名为my_custom_network的网络&#xff1a; docker network create --driver bridge my_custom_network2. 启动容器并连接到自…

单片机开发资源分析的实战——以STM32F103C8T6为例子的单片机资源分析

目录 第一点&#xff1a;为什么叫STM32F103C8T6 从资源手册拿到我们的对STM32F103C8T6的资源描述 第二件事情&#xff0c;关心我们的GPIO引脚输出 第三件事情&#xff1a;去找对应外设的说明部分 前言 本文章隶属于项目&#xff1a; Charliechen114514/BetterATK: This is…

贪心算法(9)(java)最优除法

题目&#xff1a; 给定一正整数数组 nums,nums中的相邻整数将进行浮点除法。例如&#xff0c;[2,3.4]->2/3/4. 例如&#xff0c;nums [2,3,4]&#xff0c;我们将求表达式的值“2/3/4"。 但是&#xff0c;你可以在任意位置添加任意数目的括号&#xff0c;来改变算…

腾讯云MySQL数据库架构分析与使用场景

TDSQL-C for MySQL TDSQL-C MySQL 版&#xff08;TDSQL-C for MySQL&#xff09;是腾讯云自研的新一代云原生关系型数据库。融合了传统数据库、云计算与新硬件技术的优势&#xff0c;为用户提供具备高弹性、高性能、海量存储、安全可靠的数据库服务。TDSQL-C MySQL 版100%兼容…

荣耀手机卸载应用商店、快应用中心等系统自带的

1.下载abd ADB Download - Get the latest version of ADB and fastboot 2.手机打开开发者选项 3.手机接电脑打开USB调试 4.下载MT管理器查看系统包名 D:\1.LFD\ADB\platform-tools-latest-windows\platform-tools>adb shell adb.exe: no devices/emulators found 这边是…

星型拓扑网络发生网络风暴

在星型拓扑网络中&#xff0c;所有的设备&#xff08;如计算机、打印机等&#xff09;通过一个中心设备&#xff08;通常是交换机或集线器&#xff09;连接在一起。 星型拓扑网络中发生网络风暴时的情况&#xff1a; 网络风暴的表现 1.广播风暴&#xff1a;在星型拓扑中&…

网络流基本概念及实现算法

基本概念 流网络 对于一个有向图, 抽象成水管里的水的模型, 每根管子有容量限制, 计为 G ( V , E ) G (V, E) G(V,E), 首先不考虑反向边 对于任意无向图, 都可以将反向边转化为上述形式 如果一条边不存在, 定义为容量为 0 0 0, 形式上来说就是 c ( u , v ) 0 c(u, v) 0 c(…

【css酷炫效果】纯CSS实现球形阴影效果

【css酷炫效果】纯CSS实现球形阴影效果 缘创作背景html结构css样式完整代码基础版进阶版(动态版) 效果图 想直接拿走的老板&#xff0c;链接放在这里&#xff1a;上传后更新 缘 创作随缘&#xff0c;不定时更新。 创作背景 刚看到csdn出活动了&#xff0c;赶时间&#xff0…

Linux如何在设备树中表示和引用设备信息

DTS基本知识 dts 硬件的相应信息都会写在.dts为后缀的文件中&#xff0c;每一款硬件可以单独写一份xxxx.dts&#xff0c;一般在Linux源码中存在大量的dts文件&#xff0c;对于arm架构可以在arch/arm/boot/dts找到相应的dts&#xff0c;一个dts文件对应一个ARM的machie。 dtsi 值…

【数学建模】模糊综合评价模型详解、模糊集合论简介

模糊综合评价模型详解 文章目录 模糊综合评价模型详解1. 模糊综合评价模型概述2. 模糊综合评价的基本原理2.1 基本概念2.2 评价步骤 3. 模糊综合评价的数学模型3.1 数学表达3.2 模糊合成运算 4. 模糊综合评价的应用领域5. 模糊综合评价的优缺点5.1 优点5.2 缺点 6. 模糊综合评价…

C++20 中的同步输出流:`std::basic_osyncstream` 深入解析与应用实践

文章目录 一、std::basic_osyncstream 的背景与动机二、std::basic_osyncstream 的基本原理三、std::basic_osyncstream 的使用方法&#xff08;一&#xff09;基本用法&#xff08;二&#xff09;多线程环境下的使用&#xff08;三&#xff09;与文件流的结合 四、std::basic_…

C/C++蓝桥杯算法真题打卡(Day8)

一、P8780 [蓝桥杯 2022 省 B] 刷题统计 - 洛谷 算法代码&#xff1a; #include<bits/stdc.h> // 包含标准库中的所有头文件&#xff0c;方便使用各种数据结构和算法 using namespace std; // 使用标准命名空间&#xff0c;避免每次调用标准库函数时都要加 std::in…