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

Java延迟队列

📌 1. 场景背景

最近做项目,使用到了延迟队列。场景是这样的:在在线视频学习中,学生每隔几秒上报当前学习进度,为避免频繁写数据库、提升性能,采用以下方案:

先写入 Redis,再延迟一定时间(如20秒)后持久化到数据库。


⚙️ 2. 技术方案概览

使用 Java 提供的 DelayQueue​ 处理延迟任务。

关键组成:

组件说明
DelayTask<T>封装延迟任务,定义触发时间
DelayQueue用于存放所有的延迟任务,按时间顺序触发
LearningRecordsDelayTaskHandler延迟任务的核心调度类

🧩 3. DelayTask<T>​ 延迟任务封装类

public class DelayTask<T> implements Delayed {
    private T data;
    private long deadlineNanos;

    public DelayTask(T data, Duration delayTime) {
        this.data = data;
        this.deadlineNanos = System.nanoTime() + delayTime.toNanos();
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(Math.max(0, deadlineNanos - System.nanoTime()), TimeUnit.NANOSECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        long diff = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);
        return diff > 0 ? 1 : diff < 0 ? -1 : 0;
    }
}

✅ 说明:

  • deadlineNanos​:任务到期时间(单位:纳秒)
  • 实现 Delayed​ 接口,用于 DelayQueue​ 排序与调度

🧠 4. LearningRecordsDelayTaskHandler​ 任务处理类

主要职责:

  • 管理延迟任务队列
  • 处理过期任务
  • 管理 Redis 缓存的读写

队列定义:

private final DelayQueue<DelayTask<RecordTaskData>> queue = new DelayQueue<>();

🧵 5. 初始化与销毁

@PostConstruct
public void init() {
    CompletableFuture.runAsync(this::handleDelayTask);
}

@PreDestroy
public void destroy() {
    begin = false;
}
  • 使用异步线程后台监听队列
  • 应用关闭时中止处理线程

🔄 6. 延迟任务处理流程

while (begin) {
    DelayTask<RecordTaskData> task = queue.take();
    ...
}

流程图:

前端上报进度
    ↓
写入 Redis 缓存
    ↓
提交延迟任务(20秒后)
    ↓
20秒后从 DelayQueue 取出任务
    ↓
比较任务数据与当前 Redis 数据
  → 相同:说明用户已停留 → 写库
  → 不同:用户仍在更新 → 放弃

💾 7. Redis 缓存结构与读写

  • 键:learning:record:{lessonId}
  • 字段:{sectionId}
  • 值:RecordCacheData​ 的 JSON 字符串

写入缓存:

String key = "learning:record:" + lessonId;
redisTemplate.opsForHash().put(key, sectionId, json);
redisTemplate.expire(key, Duration.ofMinutes(1));

读取缓存:

Object cacheData = redisTemplate.opsForHash().get(key, sectionId.toString());

📤 8. 添加任务到队列

queue.add(new DelayTask<>(new RecordTaskData(record), Duration.ofSeconds(20)));
  • 提交一个包含用户观看记录的延迟任务,20秒后触发处理

✅ 9. 优点总结

优点描述
⏳ 延迟写库降低数据库压力,避免频繁更新
🔁 防抖处理用户频繁上报只处理最后一次
🧠 最终一致性延迟处理保证数据最终落库
💡 简单高效基于 JDK 自带 DelayQueue,无需额外中间件

http://www.dtcms.com/a/122617.html

相关文章:

  • 铼赛智能Edge mini斩获2025法国设计大奖 | 重新定义数字化齿科美学
  • 深入解析 C++ 设计模式:原理、实现与应用
  • YOLOv12即插即用--CPAM
  • 【Kafka基础】消费者命令行完全指南:从基础到高级消费
  • 软考高级-系统架构设计师 案例题-软件架构设计
  • vue:前端预览 / chrome浏览器设置 / <iframe> 方法预览 doc、pdf / vue-pdf 预览pdf
  • 蓝桥杯 一年中的第几天(日期问题)
  • 如何运用浏览器进行各种调试?(网络、内存、控制台等调试用法)
  • 前端实战:基于Vue3与免费满血版DeepSeek实现无限滚动+懒加载+瀑布流模块及优化策略
  • Vert.x vs. Micronaut:2025年高并发Java框架选型指南
  • redisson常用加锁方式
  • 【代码模板】判断C语言中文件是否存在?错误:‘F_OK’未声明如何处理?(access;#include “unistd.h“)
  • 【智慧养猪场】-猪的行为分析视频数据集及展示(已做好分类)
  • C —— 宏
  • Redis-场景缓存+秒杀+管道+消息队列
  • 保留格式地一键翻译英文ppt
  • etf可以T+0交易吗?
  • 基础知识补充篇:什么是DAPP前端连接中的provider
  • 用网页JS实现数据添加和取出的操作,链表
  • Class 文件和类加载机制
  • 【10】数据结构的矩阵与广义表篇章
  • 聊透多线程编程-线程基础-3.C# Thread 如何从非UI线程直接更新UI元素
  • 学习MySQL的第六天
  • vue+uniapp 获取上一页直接传递的参数
  • 大数据(6)【Kettle入门指南】从零开始掌握ETL工具:基础操作与实战案例解析
  • Spring Boot 自定义配置类(包含字符串、数字、布尔、小数、集合、映射、嵌套对象)实现步骤及示例
  • PHP 表单处理详解
  • docker安装软件汇总(持续更新)
  • 2022年全国职业院校技能大赛 高职组 “大数据技术与应用” 赛项赛卷(2卷)任务书
  • (三)行为模式:12、访问者模式(Visitor Pattern)(C++示例)