模板企业快速建站营销方案怎么写
📌 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();}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(Math.max(0, deadlineNanos - System.nanoTime()), TimeUnit.NANOSECONDS);}@Overridepublic 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,无需额外中间件 |