DelayQueue实现延时任务

文章目录

    • DelayQueue
      • 基本概念
      • Delayed接口
      • 示例
      • 内部实现原理
      • 应用场景
      • 小结
    • 模拟超时订单处理
      • Order 实体类
      • OrderController 类
      • OrderService 类
      • OrderConsumer 类

DelayQueue

DelayQueue是一个有序的阻塞队列,用于在指定的延迟之后从队列中提取元素。它在调度任务、缓存清除、延迟任务处理等场景中非常有用。

基本概念

DelayQueue位于java.util.concurrent包中,它是一个无界的阻塞队列,元素必须实现Delayed接口。队列中的元素按照它们的到期时间排序,只有到期的元素才能从队列中提取。

Delayed接口

Delayed接口扩展了Comparable接口,要求实现以下方法:

  • long getDelay(TimeUnit unit): 返回元素的剩余延迟时间。
  • int compareTo(Delayed other): 用于比较元素的到期时间。
/*** Test类实现了Delayed接口* Delayed接口要求实现getDelay和compareTo方法。*/
public class Test implements Delayed {/*** 返回元素的延迟时间。* @param unit 时间单位* @return 延迟时间,单位为指定的时间单位。*/@Overridepublic long getDelay(TimeUnit unit) {return 0;}/*** 比较两个延迟元素的顺序。* @param o 另一个延迟元素* @return 比较结果,负数表示当前元素在前,正数表示当前元素在后,0表示相等。*/@Overridepublic int compareTo(Delayed o) {return 0;}
}

示例

下面是一个简单的示例,展示了如何使用DelayQueue

第一步:定义延时任务

/*** DelayTask类实现了Delayed接口,用于表示延迟任务。* @param <T> 任务数据的类型*/
@Data
public class DelayTask<T> implements Delayed {// 执行的任务数据private T data;// 任务的执行时间,使用纳秒表示private long activeTime;public DelayTask(T data, Duration delayTime) {this.data = data;this.activeTime = System.nanoTime() + delayTime.toNanos();}/*** 获取任务的剩余延迟时间。** @param unit 时间单位* @return 剩余的延迟时间,单位为指定的时间单位*/@Overridepublic long getDelay(TimeUnit unit) {// unit时间单位// 而 convert 方法用于将时间从一个单位转换到另一个单位return unit.convert(Math.max(0, activeTime - System.nanoTime()), TimeUnit.NANOSECONDS);}/*** 比较两个延迟任务的顺序。** @param o 另一个延迟任务* @return 比较结果,负数表示当前任务在前,正数表示当前任务在后,0表示相等*/@Overridepublic int compareTo(Delayed o) {long l = getDelay(TimeUnit.NANOSECONDS) - o.getDelay(TimeUnit.NANOSECONDS);if (l > 0) {return 1;} else if (l < 0) {return -1;} else {return 0;}}
}

第二步:测试

/*** DelayTaskTest类用于测试DelayQueue的使用。* 通过SpringBootTest注解加载Spring应用上下文。*/
@SpringBootTest(classes = LearningApplication.class)
@Slf4j  
public class DelayTaskTest {@Testpublic void test() throws InterruptedException {// 创建一个DelayQueue,用于存放DelayTask任务DelayQueue<DelayTask> tasks = new DelayQueue<>();tasks.add(new DelayTask("task1", Duration.ofSeconds(3)));tasks.add(new DelayTask("task2", Duration.ofSeconds(6)));tasks.add(new DelayTask("task3", Duration.ofSeconds(7)));// 无限循环,从队列中取出并执行任务while (true) {// 从队列中取出到期的任务,如果没有到期任务则阻塞等待DelayTask take = tasks.take();// 处理任务 这里仅打印log.info("{} is executed", take.getData());}}
}

DelayTaskTest类通过测试方法展示了如何使用DelayQueue来处理延迟任务。它向队列中添加了多个延迟任务,并通过无限循环从队列中取出并执行到期的任务。这种机制在定时任务调度、延迟消息处理等场景中非常有用。

取出任务用take(): 检索并移除队列头部的元素,如果没有到期元素则阻塞

内部实现原理

DelayQueue的内部实现依赖于PriorityQueuePriorityQueue保证了队列元素的自然顺序或通过提供的比较器进行排序。

  • 添加元素:当元素被添加到DelayQueue时,会根据其到期时间进行排序。【有序】
  • 提取元素:只有在getDelay()方法返回的延迟时间小于等于零时,元素才能从队列中提取出来。

应用场景

DelayQueue可以应用在以下场景:

  1. 定时任务调度:用于执行延迟任务。比如订单超时取消
  2. 缓存过期处理:在缓存中存储元素,并在元素到期时将其移除。
  3. 消息延迟处理:在消息队列中处理延迟消息。

小结

DelayQueue在处理延迟任务和定时调度任务中非常有用。通过实现Delayed接口,可以轻松地创建自定义的延迟元素,并将其添加到DelayQueue中进行管理。

模拟超时订单处理

Order 实体类

@Data
public class Order implements Delayed {private String orderId;private boolean completed;private long endTime;public Order(String orderId, Duration delayTime) {this.orderId = orderId;this.completed = false;this.endTime = System.currentTimeMillis() + delayTime.toMillis();}@Overridepublic long getDelay(TimeUnit unit) {return unit.convert(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}@Overridepublic int compareTo(Delayed o) {return Long.compare(this.getDelay(TimeUnit.MILLISECONDS), o.getDelay(TimeUnit.MILLISECONDS));}
}

OrderController 类

@RestController
@RequestMapping("/orders")
public class OrderController {@Autowiredprivate OrderService orderService;@PostMapping("/create")public String createOrder(@RequestParam String orderId, @RequestParam long delayInSeconds) {orderService.createOrder(orderId, delayInSeconds);return "Order created: " + orderId;}@PostMapping("/complete")public String completeOrder(@RequestParam String orderId) {boolean result = orderService.completeOrder(orderId);return result ? "Order completed: " + orderId : "Order not found or already completed: " + orderId;}// ...
}

OrderService 类

@Service
public class OrderService {@Autowiredprivate OrderMapper orderMapper;private final DelayQueue<Order> delayQueue = new DelayQueue<>();public OrderService() {OrderConsumer consumer = new OrderConsumer(delayQueue, this);Thread consumerThread = new Thread(consumer);consumerThread.start();}public void createOrder(String orderId, long delayInSeconds) {Order order = new Order(orderId, Duration.ofSeconds(delayInSeconds));delayQueue.add(order);orderMapper.insertOrder(order); // 插入订单到数据库}public boolean completeOrder(String orderId) {for (Order order : delayQueue) {if (order.getOrderId().equals(orderId) && !order.isCompleted()) {order.complete();orderMapper.updateOrderStatus(orderId, "COMPLETED");return true;}}return false;}public void cancelOrder(String orderId) {orderMapper.updateOrderStatus(orderId, "CANCELLED");}
}

OrderConsumer 类

@Slf4j
public class OrderConsumer implements Runnable {private final DelayQueue<Order> delayQueue;private final OrderService orderService;public OrderConsumer(DelayQueue<Order> delayQueue, OrderService orderService) {this.delayQueue = delayQueue;this.orderService = orderService;}@Overridepublic void run() {while (true) {try {Order order = delayQueue.take();if (!order.isCompleted()) {log.info("Order {} is cancelled due to timeout.", order.getOrderId());orderService.cancelOrder(order.getOrderId());} else {log.info("Order {} is completed.", order.getOrderId());}} catch (InterruptedException e) {log.error(e);}}}
}

❤觉得有用的可以留个关注~❤

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

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

相关文章

回车不搜索直接页面刷新问题解决

使用技术栈&#xff1a;vue3、elementUiPlus 问题&#xff1a;回车触发方法&#xff0c;会刷新整个页面&#xff0c;不执行搜索 解决方法&#xff1a;在搜索的表单中增加submit.native.prevent submit.native.prevent

如何理解Java中的线程是如何运作的?

当你实现 Runnable 接口并重写 run 方法时&#xff0c;run 方法本身并不会被自动调用。Runnable 接口定义了一个没有参数的 run 方法&#xff0c;这个方法包含了你希望在线程中执行的代码。 要启动一个线程并执行 run 方法中的代码&#xff0c;需要做以下几步&#xff1a; 1.…

【HBZ分享】如何规避TCP的洪水攻击

常规洪水攻击的原理 在TCP第二次握手建立半连接时&#xff0c;此时就可以发动洪水攻击就是大量的请求发起TCP连接&#xff0c;当第二次握手时&#xff0c;服务器会把这些请求放到半连接队列中&#xff0c;由于这些恶意攻击的客户端不会再确认第三次握手&#xff0c;就导致这些…

接口幂等和防抖还在傻傻分不清楚。。。

最近想重温下接口幂等的相关知识&#xff0c;正所谓温故而知新&#xff0c;太久不CV的东西要是哪天CV起来都生疏了&#xff0c;哈哈哈 先从字面意思来温习下吧&#xff0c;幂等的官方概念来源于数学上幂等概念的衍生&#xff0c;如幂等函数&#xff0c;即使用相同的参数重复执…

GeoTrust ——适合企业使用的SSL证书!

GeoTrust是一家全球知名的数字证书颁发机构&#xff08;CA&#xff09;&#xff0c;其提供的SSL证书非常适合企业使用。GeoTrust的SSL证书为企业带来了多重优势&#xff0c;不仅在验证级别、加密强度、兼容性、客户服务等方面表现出色&#xff0c;而且其高性价比和灵活的证书选…

arm操作系统的板子 怎么实现远程控制

安装适配arm操作系统的todesk 程序ToDesk远程桌面软件-免费安全流畅的远程连接电脑手机

C 语言中如何实现图结构?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; &#x1f4d9;C 语言百万年薪修炼课程 【https://dwz.mosong.cc/cyyjc】通俗易懂&#xff0c;深入浅出&#xff0c;匠心打磨&#xff0c;死磕细节&#xff0c;6年迭代&…

PHP MySQL 简介

PHP MySQL 简介 PHP 和 MySQL 是现代网站开发中最流行的两种技术。PHP 是一种服务器端脚本语言&#xff0c;而 MySQL 是一种关系型数据库管理系统。这两种技术经常一起使用&#xff0c;以创建动态和交互式的网页。本文将简要介绍 PHP 和 MySQL 的基本概念、它们的工作原理以及…

[图解]分析模式-01-概述1

1 00:00:01,380 --> 00:00:01,770 好 2 00:00:02,340 --> 00:00:06,440 非常感谢大家能够来上我们 3 00:00:06,450 --> 00:00:07,960 分析模式高阶的课程 4 00:00:09,310 --> 00:00:13,440 这个内容之前在分析设计高阶 5 00:00:13,450 --> 00:00:17,840 也就…

C++ 指针变量做参数传递时的情况分析

前言 指针变量作为参数传递时&#xff0c;很容易混淆指针本身和指针指向的内容&#xff0c;实际应用中可能会导致无法预料的问题&#xff0c;所以做一下详细分析。 注意&#xff0c;在测试过程中为了看测试效果&#xff0c;有些指针变量分配了空间&#xff0c;但是未做回收&am…

电气常用知识

1、常开、常闭 在不加外力作用下&#xff0c;展示的状态就是常 因此&#xff0c;常开就是在不加外力作用下的 开的状态&#xff0c;也就是断开的状态 常闭就是在不加外力作用下的闭合的状态&#xff0c;也就是闭合的状态 2、单控双控 单控&#xff1a;一个东西只有两种状态…

Ubuntu 修改~/.bashrc终端选择是否使用annconda环境

首先需要明白的是anaconda虽然自带了python&#xff0c;但安装anaconda后并不会覆盖掉你原来的python&#xff08;pip也是一样的&#xff09;&#xff0c;但安装anaconda后它会把自己的bin目录&#xff08;里面有python、pip、conda等命令&#xff09;加到PATH上&#xff0c;而…

Javassist 修改 jar 包里的 class 文件

前言 Javassist 是一个用于处理 Java 字节码的类库&#xff0c;可以用以修改 class 文件或 jar 包里的 class 文件。 简单来说我们用Java编写的代码是放在 java 格式的代码文件里&#xff0c;在编译的时候会编译为 class 格式的字节码文件&#xff0c;然后一般所有 class 文件…

GitHub每日最火火火项目(7.12)

项目名称&#xff1a;public - apis / public - apis 项目介绍&#xff1a;这是一个集体列表&#xff0c;包含了各种免费的 API。该项目可能致力于收集和整理不同领域的免费 API&#xff0c;为开发者提供便利&#xff0c;使其能够更轻松地获取所需的数据和功能。通过使用这些免…

腾讯面试:let、const解决了什么问题?

前言 今天来聊一聊腾讯的一个面试题&#xff0c;let、const解决了什么问题&#xff1f; let、const解决了什么问题&#xff1f; 我们来分析一下这个问题 首先这个问题问我们let、const解决了什么问题&#xff1f; 我们就需要去分别讲解一个let和const是干什么用的 首先le…

雅思词汇及发音积累 2024.7.12

问卷调查 poll /pəʊl/ 民意调查 survey 调查 sample 样本 respondent 调查对象 interviewee 被采访的人 interview 采访,访谈 questionnaire 调查问卷 observation 观察 rank 排序 rate 打分 classification 分类 hypothesis /haɪˈpɒθəsɪs/ 假设 statistics 统计 sta…

宝马退出价格战,19万买不到i3了

ChatGPT狂飙160天&#xff0c;世界已经不是之前的样子。 更多资源欢迎关注 宝马退出价格战 这一消息&#xff0c;源自知名汽车博主孙少军。 7月11日他发文称&#xff0c;“因价格战导致门店亏损严重&#xff0c;宝马7月将会开始降量保价。” 第二天他又做了补充&#xff0c…

FastAPI 学习之路(四十二)利用Docker部署发布

我们之前的部署都是基于本地的部署&#xff0c;我们这次来看下&#xff0c;如何使用docker部署我们的fastapi项目。 编写Dockerfile ①&#xff1a;首先编写一个docker镜像的制作文件Dockerfile FROM python:3.10RUN pip install fastapi uvicorn aiofiles sqlalchemy pytho…

数据建设实践之大数据平台(七)安装dolphinscheduler

安装DS 上传安装包到/opt/software目录并解压 [bigdata@node101 software]$ tar -zxvf apache-dolphinscheduler-3.1.9-bin.tar.gz 授权 [bigdata@node101 software]$ chown -R bigdata:bigdata /opt/software/apache-dolphinscheduler-3.1.9-bin 配置install_env.…

【LeetCode】633. 平方数之和

1. 题目 2. 分析 典型双指针的题了&#xff0c;不知道为啥LeetCode会把这题放到二分类别下&#xff1f; 需要知道math.ceil()是向上取整&#xff1b; 3. 代码 class Solution:def judgeSquareSum(self, c: int) -> bool:upper math.ceil(sqrt(c))print(upper)left, ri…