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

基于DelayQueue实现的延时队列

基于java中延时队列的实现该文章,我们这次主要是来实现基于DelayQueue实现的延时队列。

使用DelayQueue实现的延时队列的步骤:

  1. 定义一个继承了Delayed的类,定义其中的属性,并重写compareTogetDelay两个方法
  2. 创建一个Delayqueue用于创建队列
  3. 创建一个生产者,用于将信息添加到队列中
  4. 创建一个消费者,用来从队列中取出信息进行消费

接下来是一个简单的demo :

定义一个元素类


import lombok.Data;import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;@Data
public class DelayTesk implements Delayed {//标签Idprivate String uid;//到期时间private Long timestamp;//延时信息private String data;@Overridepublic long getDelay(TimeUnit unit) {long delayTime = timestamp - System.currentTimeMillis();//将时间转换成毫秒(这边可转可不转,影响不大)return unit.convert(delayTime, TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {//针对任务的延时时间长短进行排序,把延时时间最短的放在前面long differenceTime = this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS);return (int)differenceTime;}
}

定义一个延时队列


import java.util.concurrent.DelayQueue;public class DelayTaskQueue {/*** 这边使用单例模式进行创建,保证全局队列的唯一性* 我这边使用的是双检索,双校验模式*/private volatile static DelayQueue<DelayTesk> delayTaskQueue;private DelayTaskQueue(){}public static DelayQueue<DelayTesk> getDelayTaskQueue() {if (delayTaskQueue == null) {synchronized (DelayTaskQueue.class) {if (delayTaskQueue == null) {delayTaskQueue = new DelayQueue<>();}}}return delayTaskQueue;}
}

创建一个延时队列的生产者

import lombok.extern.slf4j.Slf4j;import java.util.concurrent.DelayQueue;//消息生产者
@Slf4j
public class DelayTeskQueueProducer {/***  往延时队列中插入数据* @param uid* @param time* @param data*/public static void setDelayQueue(String uid, Long time, String data) {//创建队列DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();//创建任务DelayTesk delayTesk = new DelayTesk();delayTesk.setUid(uid);delayTesk.setTimestamp(time);delayTesk.setData(data);log.info("====================消息入队:{}===============", uid);boolean res = delayTaskQueue.offer(delayTesk);if (res) {log.info("====================消息入队成功:{}===============", uid);} else {//如果消息入队失败这边可以写一个失败的回调函数//例如将失败的消息存入数据库,写个定时任务对消息进行重写投递……log.info("====================消息入队失败:{}===============", uid);}}
}

定义一个延时队列的消费者

import cn.hutool.core.util.IdUtil;
import lombok.extern.slf4j.Slf4j;import java.util.concurrent.DelayQueue;@Slf4j
public class DelayTeskQueueConsumer {public static void main(String[] args) {for (int i = 0; i < 10 ; i++) {DelayTeskQueueProducer.setDelayQueue(IdUtil.fastUUID(), System.currentTimeMillis() + i * 1000, "hello world" + i);}int index = 0;DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();while (index < 10) {try {DelayTesk delayTesk = delayTaskQueue.take();System.out.println(delayTesk.getData());} catch (InterruptedException e) {log.error("延时队列消费异常:{}", e.getMessage());}}}
}

结果
在控控制台中每隔1秒打印一行数据
在这里插入图片描述

到这差不多我们的Demo就要结束了,不过可能有些同学会问,你这个消费者不是是写在mian方法里的,每次消费的时候都需要手动去调用这跟我直接用sleep函数实现的延时队列有啥区别呀

别急 这个只是个Demo嘛,如果需要使用在项目中可以写一个监听器去实时监听该延时队列
我这边暂时就只讲3种

Timer

通过timer定时定频率去获取DelayTaskQueue中的消息

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.DelayQueue;/***  添加@Configuration  注解,自动注入实例对象,并由springboot 启动 定时器,执行任务。*/@Configuration
@Slf4j
public class DelayTeskQueueTimer {@Beanpublic void DelayTeskQueueTimer() {log.info("====================监听开始====================");final Timer timer = new Timer();DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();timer.schedule(new TimerTask() {@Overridepublic void run() {try {DelayTesk delayTesk = delayTaskQueue.take();System.out.println(delayTesk.getData());} catch (Exception e) {log.error("延时队列消费异常:{}", e.getMessage());}}//第一次执行是在当前时间的一秒之后,之后每隔一秒钟执行一次},1000, 1000);}
}

ConmandlineRunner

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Configuration;import java.util.concurrent.DelayQueue;
/*** Spring Boot应用程序在启动后,程序从容器中遍历实现了CommandLineRunner接口的实例并运行它们的run方法*/
@Slf4j
@Configuration
public class DelayTeskQueueTimerCommandLineRunner implements CommandLineRunner {@Overridepublic void run(String... args) {log.info("====================CommandLineRunner监听开始====================");DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();new Thread(() ->{while (true) {try {DelayTesk delayTesk = delayTaskQueue.take();System.out.println(delayTesk.getData());} catch (Exception e) {log.error("延时队列消费异常:{}", e.getMessage());}}}).start();}
}

ApplicationListener

该方法和ConmandlineRunner方法一样 都是在Spring Boot应用程序在启动后,对DelayQueue进行监听

import com.study.project.delay.DelayTaskQueue;
import com.study.project.delay.DelayTesk;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;import java.util.concurrent.DelayQueue;@Slf4j
@Configuration
public class DelayTeskQueueApplicationListener implements ApplicationListener<ContextRefreshedEvent> {@Overridepublic void onApplicationEvent(ContextRefreshedEvent event) {log.info("====================ApplicationListener监听开始====================");DelayQueue<DelayTesk> delayTaskQueue = DelayTaskQueue.getDelayTaskQueue();new Thread(() -> {while (true) {try {DelayTesk delayTesk = delayTaskQueue.take();System.out.println(delayTesk.getData());} catch (Exception e) {log.error("延时队列消费异常:{}", e.getMessage());}}}).start();}
}

当然监听的方法其实还有很多,不过同学们在实现队列的时候不要觉得实现了就好了,要去思考如何去保证数据的持久化,保证数据不会不会丢失

相关文章:

基于DelayQueue实现的延时队列

基于java中延时队列的实现该文章&#xff0c;我们这次主要是来实现基于DelayQueue实现的延时队列。 使用DelayQueue实现的延时队列的步骤&#xff1a; 定义一个继承了Delayed的类&#xff0c;定义其中的属性&#xff0c;并重写compareTo和getDelay两个方法创建一个Delayqueue…...

MATLAB实现层次分析法AHP及案例分析

层次分析法(Analytic Hierarchy Process, AHP) 1 模型背景 美国运筹学家匹兹堡大学教授Saaty在20世纪70年代初提出的一种层次权重决策分析方法。 层次分析法(Analytic Hierarchy Process, AHP)是一种定性和定量分析相结合的决策分析方法。 特点:用较少的定量信息使决策的…...

Vue 3.0 TypeScript支持

Vue CLI 提供内置的 TypeScript 工具支持。 #NPM 包中的官方声明 随着应用的增长&#xff0c;静态类型系统可以帮助防止许多潜在的运行时错误&#xff0c;这就是为什么 Vue 3 是用 TypeScript 编写的。这意味着在 Vue 中使用 TypeScript 不需要任何其他工具——它具有一流的公…...

STM8S系列基于IAR标准外设printf输出demo

STM8S系列基于IAR标准外设printf输出demo&#x1f4cc;STM8S/A标准外设库&#xff08;库版本V2.3.1&#xff09;&#x1f4cd;官网标准外设库&#xff1a;https://www.st.com/zh/embedded-software/stsw-stm8069.html ⛳注意事项 &#x1f6a9;在内存空间比较有限的情况下&am…...

PMP项目管理项目质量管理

目录1 项目质量管理概述2 规划质量管理3 管理质量4 控制质量1 项目质量管理概述 项目质量管理包括把组织的质量政策应用于规则、管理、控制项目和产品质量要求&#xff0c;以满足相关方目标的各个过程。项目质量管理还将以组织的名义支持过程的持续改进活动。 核心概念 质量是…...

前缀和总结

前缀和是一个常用的算法技巧,通常用于求解数组或序列的区间和。 具体来说,假设有一个长度为n的数组a,我们可以预处理出一个长度为n+1的前缀和数组s,其中s[i]表示原数组a前i个元素的和,即: s[i] = a[0] + a[1] + ... + a[i-1] 这样一来,对于任意的区间[l, r],我们可以…...

0109二分图-无向图-数据结构和算法(Java)

文章目录1 概念2 API3 分析和实现4 测试5 总结后记1 概念 二分图是一种能将所有结点分为两部分的图&#xff0c;其中图的每条边所连接的两个顶点都分别属于不同的部分。 2 API public classBipartiteBipartite(Graph G)预处理函数public booleanisBipartitle()是否是二分图pub…...

计算机网络题库---选择题刷题训练(100多道精品)

第一章 概述 1.下列四项内容中&#xff0c;不属于Internet&#xff08;因特网&#xff09;基本功能是___D_____。 A.电子邮件 B.文件传输 C.远程登录 D.实时监测控制 2.Internet是建立在____C_____协议集上的国际互联网络。 A.IPX B.NetBEUI C.TCP/IP …...

16、字符串生成器

目录 &#xff08;1&#xff09;append()方法 &#xff08;2&#xff09;insert(int offset, arg)方法 &#xff08;3&#xff09;delete(int start , int end)方法 创建成功的字符串对象&#xff0c;其长度是固定的&#xff0c;内容不能被改变和编译。虽然使用“”可以达到…...

docker基本命令-容器

容器 基本概念 镜像&#xff08;Image&#xff09;和容器&#xff08;Container&#xff09;的关系&#xff0c;就像是面向对象程序设计中的 类 和 实例 一样&#xff0c;镜像是静态的定义&#xff0c;容器是镜像运行时的实体。容器可以被创建、启动、停止、删除、暂停等。 容…...

QT入门基础(一)

文章目录零.Qt背景1.什么是Qt2.Qt的发展史3.Qt的优势4.Qt应用一.第一个Qt程序0.项目创建1.main函数文件2.类头文件3.pro文件4.qt命名规范二.Qt按钮1.按钮创建和父子关系2.按钮常用api3.Qt窗口坐标体系4.对象树模型零.Qt背景 1.什么是Qt Qt是一个跨平台的C图形用户界面应用程序…...

WattOS:一个稳又快的轻量级 Linux 发行版

导读Linux 领域里的每个人不是听说过就是使用过某个轻量级的 Linux 发行版。大家都知道我们不断追求的是&#xff1a;占用内存少&#xff0c;配置资源要求低&#xff0c;包含一个轻量级的桌面环境&#xff08;或者窗口管理器&#xff09;&#xff0c;并且提供和其他发行版相似的…...

Java调用Python脚本:轻松实现两种语言的互操作性

Java和Python都是非常流行的编程语言&#xff0c;它们都有自己的优点&#xff0c;但也有自己的局限性。在编写应用程序时&#xff0c;我们可能需要使用两种语言来共同完成一项任务。在这种情况下&#xff0c;Java需要调用Python脚本来解决某些问题&#xff0c;同时利用Java和Py…...

未系安全带识别系统 yolo

未系安全带识别系统通过pythonyolo智能视频分析技术&#xff0c;未系安全带识别算法对画面中高空作业人员未系安全带行为进行监测&#xff0c;未系安全带识别算法监测到人员未穿戴安全带时&#xff0c;立即通知后台人员及时处理触发告警。Yolo算法采用一个单独的CNN模型实现end…...

(七十六)大白话MySQL是如何根据成本优化选择执行计划的?(上)

之前已经给大家讲解清楚了 MySQL 在执行单表查询时候的一些执行计划&#xff0c;比如说const、ref、range、index、all之类的&#xff0c;也讲了多表关联的时候是如何执行的&#xff0c;本质其实就是先查一个驱动表&#xff0c;接着根据连接条件去被驱动表里循环查询&#xff0…...

DSRC技术

DSRC(Dedicated Short Range Communication)专用短程通信 定位 是V2X领域存在的两大通信技术之一&#xff08;另一个为LTE-V2X&#xff09;。 所属技术路线 与这两大技术相对应&#xff0c;是V2X无线通信技术的两大技术路线&#xff1a; IEEE 802.11p 本是04年指定的一个通…...

_面经问题_

一、Java编程语言 Java语言有哪些特点? JVM vs JDK vs JRE 什么是字节码? 采用字节码的好处是什么? 为什么不全部使用AOT呢? 为什么说Java语言"编译与解释并存"? Oracle JDK vs OpenJDK Java和C的区别? 注释有哪几种形式? 标识符和关键字的区别是什么? Jav…...

刷题记录(2023.3.6 - 2023.3.11)

我很喜欢这周的感觉&#xff0c;前两道题对着 wp 简略复现了一下&#xff0c;由于以前都是自己学习&#xff0c;对一些稍微多、稍微难的题都会马上避开&#xff0c;笨小孩逃避太久了&#xff0c;有些事逃不掉&#xff0c;总得面对&#xff0c;开始往往很难&#xff0c;多花点时…...

14 Day:同步锁与操作系统输入输出

前言&#xff1a;在上一期的线程章节中&#xff0c;我们的线程输出貌似有大问题&#xff0c;今天我们便要来学习同步锁来解决这个问题&#xff0c;同时再次基础上拿下键盘输入&#xff0c;实现操作系统的输入和输出。从今天开始我们的操作系统不在是一块“看板”了&#xff01;…...

Gradle 的下载安装教程

Gradle 8.0.1 下载安装教程笔者的环境&#xff1a; Java 17.0.1 Gradle 8.0.1 Windows 10 教育版 64位 在继续阅读本教程之前&#xff0c;需要先完成 JDK 的安装。JDK 需要选择 8 及以上的版本。关于 JDK 的安装&#xff0c;可见笔者的另一篇博客&#xff1a; Java 的下载安…...

Linux 文件类型,目录与路径,文件与目录管理

文件类型 后面的字符表示文件类型标志 普通文件&#xff1a;-&#xff08;纯文本文件&#xff0c;二进制文件&#xff0c;数据格式文件&#xff09; 如文本文件、图片、程序文件等。 目录文件&#xff1a;d&#xff08;directory&#xff09; 用来存放其他文件或子目录。 设备…...

Python爬虫(二):爬虫完整流程

爬虫完整流程详解&#xff08;7大核心步骤实战技巧&#xff09; 一、爬虫完整工作流程 以下是爬虫开发的完整流程&#xff0c;我将结合具体技术点和实战经验展开说明&#xff1a; 1. 目标分析与前期准备 网站技术分析&#xff1a; 使用浏览器开发者工具&#xff08;F12&…...

04-初识css

一、css样式引入 1.1.内部样式 <div style"width: 100px;"></div>1.2.外部样式 1.2.1.外部样式1 <style>.aa {width: 100px;} </style> <div class"aa"></div>1.2.2.外部样式2 <!-- rel内表面引入的是style样…...

HTML前端开发:JavaScript 常用事件详解

作为前端开发的核心&#xff0c;JavaScript 事件是用户与网页交互的基础。以下是常见事件的详细说明和用法示例&#xff1a; 1. onclick - 点击事件 当元素被单击时触发&#xff08;左键点击&#xff09; button.onclick function() {alert("按钮被点击了&#xff01;&…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

Typeerror: cannot read properties of undefined (reading ‘XXX‘)

最近需要在离线机器上运行软件&#xff0c;所以得把软件用docker打包起来&#xff0c;大部分功能都没问题&#xff0c;出了一个奇怪的事情。同样的代码&#xff0c;在本机上用vscode可以运行起来&#xff0c;但是打包之后在docker里出现了问题。使用的是dialog组件&#xff0c;…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用

文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么&#xff1f;1.1.2 感知机的工作原理 1.2 感知机的简单应用&#xff1a;基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...

小木的算法日记-多叉树的递归/层序遍历

&#x1f332; 从二叉树到森林&#xff1a;一文彻底搞懂多叉树遍历的艺术 &#x1f680; 引言 你好&#xff0c;未来的算法大神&#xff01; 在数据结构的世界里&#xff0c;“树”无疑是最核心、最迷人的概念之一。我们中的大多数人都是从 二叉树 开始入门的&#xff0c;它…...