Delayed 延时任务

延时任务与定时任务的区别

延时任务,可以理解为定时任务的一种,但是他们是有区别的。
延时任务:将程序代码延时执行,执行完毕,即为结束。
定时任务:周期性执行任务。代码执行完毕后,并不意味着结束,会根据定时的周期时间,继续下次的执行。

如何做定时任务?

之前做过一期的博客:Redis做定时任务
但是是有错误的。我把redis的那个空间变动通知当成定时了!其实他应该算是延时。。。。
那如何做呢?

  • java自带的延时队列
  • redis空间变动通知
  • 可使用定时任务的那种任务调度器做:设置好时间,执行一次,然后关闭。
  • ……
实操

新的项目新的需求,一个物联网那个项目。设备爆出警报来后,用户可以设置忽略误报,在多少时间内,不在提示这个错误。
对应到数据上,就是报警数据的[字段:处理状态]修改为已处理,就查不到报警信息了。但是忽略时间一到,状态会自动改回未处理

刚开始,我是想使用Redis来做的,但是想使用redis,就必须修改配置文件,服务器不在我们手里,修改不了,这个方案被pass掉了。
然后,我使用项目中自带的任务调度器xxl-job(开源的任务调度器,跟Quartz一样的东西),自己计算cron表达式,添加任务,启动任务,然后执行修改方法,关闭任务。但是么,最后。。。被领导臭骂了一顿。说是用延时队列来做。。。

创建操作类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.jetbrains.annotations.NotNull;import java.util.List;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;@Data
@NoArgsConstructor
@AllArgsConstructor
public class DelayedAlarm implements Delayed {/*** 过期时间。这个时间一定是一个Date类型转成的*/private Long expireTime;/*** 集合ID*/private List<String> alarmIds;/*** 是否过期。小于等于0的,表示过期,大于0的,表示未过期,其差值表示还有多少时间过期。* 这个我踩了一个大坑。我写的代码为啥就是不会延时执行?* 因为这个方法表示还有多少时间过期,一定是过期时间减去当前时间,还剩下多少时间。* 而我直接unit.convert(expireTime,TimeUnit.MILLISECONDS)了,* 因为只是做了一下时间的转换,每次java调用这个方法判断还有多长时间过期,一直是这个数,所以他就一直延时。。。。* @param unit 时间的单位* @return 返回排序结果*/@Overridepublic long getDelay(@NotNull TimeUnit unit) {return unit.convert(expireTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);}/*** 排序方法。用于排序,因为放进来的对象,根据延时时间的大小,不一定是排在后面的,,有可能是排在前面的。* @param o 刚加入对象* @return 返回排序结果*/@Overridepublic int compareTo(@NotNull Delayed o) {return (int) (this.getDelay(TimeUnit.MILLISECONDS) - o.getDelay(TimeUnit.MILLISECONDS));}
}
业务调用
//省略不重要的导入
public class AlarmServiceImpl {//省略其他不重要的注入。private final DelayQueue<DelayedAlarm> DELAY_QUEUE = new DelayQueue<>();@PostConstructpublic void updateAlarmStatusQueue() {//因为是本地缓存的队列,重启服务会丢失,需要重新查库,重新添加队列List<AlarmInfo> list = alarmInfoMapper.getIgnoreAlarmList();list.forEach(entity -> {long timeDiff = System.currentTimeMillis() - entity.getAlarmStartTime().getTime();long expireTime = entity.getIgnoreTime() * 1000L;if (expireTime > timeDiff) {//当前忽略时间>时间差expireTime = expireTime - timeDiff;} else {expireTime = 0;}DELAY_QUEUE.put(new DelayedAlarm(expireTime, Arrays.asList(entity.getId())));});//这个地方。等价于 ThreadPoolExecutor executor=Executors.newSingleThreadExecutor()。//阿里巴巴代码扫描,总是飘黄,我给改了一下。。ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>(),new DefaultThreadFactory("alarm_delaye_queue"));executor.execute(new Thread(() -> {while (true) {try {DelayedAlarm take = DELAY_QUEUE.take();//获取id集合,执行业务逻辑this.updateAlarmStatus(take.getAlarmIds());log.info("延时执行队列成功");} catch (Exception e) {//注意:一定要捕获异常,否则出现异常while循环就结束了。log.error("延时执行队列失败", e);}}}));}/*** 忽略误报时间到了,自动修改警报信息状态:已处理-->未处理* @param alarmIds 警报信息ID 集合* @return*/public void updateAlarmStatus(List<String> alarmIds) {List<AlarmInfo> list = new ArrayList<>();alarmIds.forEach(id -> {//开始更新警报信息状态list.add(new AlarmInfo().setId(id).setStatus(UN_DISPOSED.getType()).setLastModifyUserId(userUtil.getUserId()));});//集成了mybaits-plus 插件,我代码给删除了,大家用的时候需要自己写Mapperthis.updateBatchById(list);log.info("延时执行修改报警信息状态成功:{}",JSONObject.toJSONString(alarmIds));}/*** 将当前的忽略误报信息添加延时队列* @param ids 警报信息ID 集合* @param expireTime 过期时间*/public void handleIgnoreAlarm(List<String> ids,Date expireTime) {//省略不重要的业务。。。。//添加队列DELAY_QUEUE.put(new DelayedAlarm(expireTime.getTime(), ids));}
}

最后看一下执行结果
在这里插入图片描述

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

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

相关文章

零基础安装分布式数据服务注册系统

一、先安装VM虚拟机&#xff0c;安装最新的ubuntu22系统&#xff0c; 先安装mysql&#xff0c; sudo apt install mysql-server sudo mysql_secure_installation 根据自己需求选择 密码安全级别时&#xff0c;选择n 删除匿名用户&#xff1f;&#xff08;按y|Y表示是&…

【算法挨揍日记】day23——740. 删除并获得点数、LCR 091. 粉刷房子

740. 删除并获得点数 740. 删除并获得点数 题目描述&#xff1a; 给你一个整数数组 nums &#xff0c;你可以对它进行一些操作。 每次操作中&#xff0c;选择任意一个 nums[i] &#xff0c;删除它并获得 nums[i] 的点数。之后&#xff0c;你必须删除 所有 等于 nums[i] - 1…

PyCharm:PyCharm新建.py文件时自动带出指定内容

在pycharm中加上指定内容&#xff0c;每次新建.py文件都会自动带出指定内容 操作&#xff1a; File—Setting—Editor----File and Code Templates--Python Script 在右侧窗口中加上如下信息 # encoding: utf-8 # author: Jeffrey # file: ${NAME}.py # time: ${DATE} ${TI…

Kettle 简介

1. PDI结构简介 图 1‑1 PDI核心组件 Spoon是构建ETL Jobs和Transformations的工具。Spoon可以以拖拽的方式图形化设计&#xff0c;能够通过spoon调用专用的数据集成引擎或者集群。 Data Integration Server是一个专用的ETL Server&#xff0c;它的主要功能有&#xff1a; 功能…

MES集成 | 集成标准不统一?看得帆云iPaaS怎么应对

得帆信息结合自身丰富实施经验及众多实践案例&#xff0c;编写了《得帆云 AIGC低代码PaaS平台系列白皮书——MES集成应用》&#xff0c;希望能为正在使用MES产品的企业数字化转型领导者和IT人员带来一些帮助。 MES是众多大型生产制造型企业在做生产执行管理时会实施的一套系统。…

魔众文库系统 v5.6.0 DWG文件格式支持,部分数据封面显示异常,定时调度清理临时文件

魔众文库系统基于文档系统知识&#xff0c;建立平台与领域&#xff0c;打造流量、用户、付费和变现的闭环&#xff0c;帮助您更好的搭建文库系统。 魔众文库系统发布v5.6.0版本&#xff0c;新功能和Bug修复累计17项&#xff0c;DWG文件格式支持&#xff0c;部分数据封面显示异…

Pytorch torch.normal()的用法

该函数原型如下&#xff1a; normal(mean, std, *, generatorNone, outNone) 该函数返回从单独的正态分布中提取的随机数的张量&#xff0c;该正态分布的均值是mean&#xff0c;标准差是std。 用法如下&#xff1a;我们从一个标准正态分布N&#xff5e;(0,1)&#xff0c;提取…

Python如何实现模板方法设计模式?什么是模板方法设计模式?Python 模板方法设计模式示例代码

什么是模板方法&#xff08;Template Method&#xff09;设计模式&#xff1f; 模板方法&#xff08;Template Method&#xff09;是一种行为型设计模式&#xff0c;它定义了一个算法的骨架&#xff0c;将一些步骤延迟到子类中实现。这种模式允许子类为一个算法的特定步骤提供…

前后端黄金组合:Django+Vue+Element UI,助你构建完美平台!

这是一篇什么文章&#xff1f; 一篇你对测试开发工作感兴趣&#xff0c;想了解系统工作逻辑的文章。 一篇是你在开始动手搭建环境前需要了解各工具原理的文章。 这是一篇你真正开始前需要查阅的文章。 本文介绍了前后端工作原理&#xff0c;前后端搭建的流程、搭建过程中需…

SQLMAP --TAMPER的编写

跟着师傅的文章进行学习 sqlmap之tamper脚本编写_sqlmap tamper编写-CSDN博客 这里学习一下tamper的编写 这里的tamper 其实就是多个绕过waf的插件 通过编写tamper 我们可以学会 在不同过滤下 执行sql注入 我们首先了解一下 tamper的结构 这里我们首先看一个最简单的例子…

Excel数据可视化—波士顿矩阵图【四象限图】

EXCEL系列文章目录 Excel系列文章是本人亲身经历职场之后萌发的想法&#xff0c;为什么Excel覆盖如此之广&#xff0c;几乎每个公司、学校、家庭都在使用&#xff0c;但是它深藏的宝藏功能却很少被人使用&#xff0c;PQ、BI这些功能同样适用于数据分析&#xff1b;并且在一些需…

Kubernetes(k8s)进阶

文章目录 Kubernetes进阶一、Namespace&#xff08;名称空间&#xff09;1.namespace介绍2.管理namespace查看namespace创建namespace删除namespaceyaml文件配置namespace 二、Pod&#xff08;最小基本部署单元&#xff09;1.pod介绍2.管理pod创建并运行pod查看pod信息访问pod删…

一周互联网简讯 | 本周互联网发生了啥?(第3期)

1.百度T7跳槽字节3-1&#xff0c;总包145万&#xff0c;压力太大想降级 硕士毕业工作10年&#xff0c;一百度T7大头兵发文称&#xff0c;自己最近拿到字节3-1的offer&#xff0c;年包从现有的110万涨30%到145万。但是担心去字节后因为定的职级高需要带人&#xff0c;压力会很大…

【Highway-env】IntersectionEnv代码阅读

文章目录 主要完成任务代码结构1.action space2.default_config3.reward_agent_rewards_agent_reward_reward_rewards小结 4.terminated & truncated5.reset_make_road_make_vehicles_spawn_vehicle 6.step 主要完成任务 IntersectionEnv继承自AbstractEnv,主要完成以下4个…

【django+vue】项目搭建、解决跨域访问

笔记为自我总结整理的学习笔记&#xff0c;若有错误欢迎指出哟~ 【djangovue】项目搭建、解决跨域访问 djangovue介绍vue环境准备vue框架搭建1.创建vue项目2.配置vue项目3.进入项目目录4.运行项目5.项目文件讲解6.vue的扩展库或者插件 django环境准备django框架搭建1.使用conda…

day29_Servlet

今日内容 零、 复习昨日 一、Servlet 零、 复习昨日 一、Servlet 1.1 Servlet介绍 javaweb开发,就是需要服务器接收前端发送的请求,以及请求中的数据,经过处理(jdbc操作),然后向浏览器做出响应. 我们要想在服务器中写java代码来接收请求,做出响应,我们的java代码就得遵循tomca…

k8s ingress高级用法一

前面的文章中&#xff0c;我们讲述了ingress的基础应用&#xff0c;接下来继续讲解ingress的一些高级用法 一、ingress限流 在实际的生产环境中&#xff0c;有时间我们需要对服务进行限流&#xff0c;避免单位时间内访问次数过多&#xff0c;常用的一些限流的参数如下&#x…

工作电压范围,转换速率高,相位补偿等特性的双运算放大器芯片D4510的描述

D4510是一块双运算放大器&#xff0c;具有较宽的工作电压范围&#xff0c;转换速率高&#xff0c;相位补偿等特性。电路能在低电源电压下:工作,电源电压范围:双电源为1V-3.5V和单电源电压为2V~7V。 主要特点&#xff1a; ● 低电压工作 ● 转换速率高 ● 动态输…

docker中怎么启动容器

1、首先在linux中使用以下命令来启动 Docker 服务&#xff1a; sudo systemctl start docker2、然后下面的命令显示所有的容器列表&#xff0c;包括正在运行和已停止的容器。 docker ps -a然后找到容器ID 3、使用 docker start 启动一个已停止的容器&#xff1a; docker s…

简单模拟 Spring 创建的动态代理类(解释一种@Transactional事务失效的场景)

模拟 Spring 创建的动态代理类 本文主要目的是从父类和子类继承的角度去分析为什么在 Service 标注的业务类中使用 this 调用方法会造成事务失效。解释在这种情况下 this 为什么是原始类对象而不是代理类对象。 问题描述 在 Service 标注的业务类中&#xff0c;如果调用本类…