Java延迟任务

news2024/9/23 15:41:34
什么是延迟任务

我们把需要延迟执行的任务叫做延迟任务,比如业务中用户发送审配,过期后需要执行一些操作,网上订单未支付,红包过期取消等等。

Java API 实现延迟任务
  • ScheduledExecutorService实现延迟任务
public static void main(String[] args) {
    ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
    System.out.println("程序启动时间:" + LocalDateTime.now());
    executor.schedule(() -> {
        System.out.println("start delay task!" + LocalDateTime.now());
    }, 4, TimeUnit.SECONDS);
}

ScheduledExecutorService可以延迟任务,也可以延迟任务后使用固定频率再执行任务。

  • DelayQueue延迟任务

DelayQueue泛型参数得实现Delayed接口,Delayed继承了Comparable接口。

getDelay方法返回这个任务还剩多久时间可以执行,小于0的时候说明可以这个延迟任务到了执行的时间了。

compareTo这个是对任务排序的,保证最先到延迟时间的任务排到队列的头。

public static void main(String[] args) throws InterruptedException {

    DelayQueue<DelayItem> delayItemQueue = new DelayQueue<>();

    delayItemQueue.put(new DelayItem("task1", 2000l));
    delayItemQueue.put(new DelayItem("task2", 5000l));
    System.out.println("start task" + LocalDateTime.now());
    while (!delayItemQueue.isEmpty()) {
        DelayItem take = delayItemQueue.take();
        System.out.println(take.getTaskContent() + " " + LocalDateTime.now());
    }

}


static class DelayItem implements Delayed {

    private final String taskContent;

    private Long triggerTime = System.currentTimeMillis();


    public DelayItem(String taskContent, Long delayTime) {
        this.taskContent = taskContent;
        this.triggerTime = this.triggerTime + delayTime;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return unit.convert(triggerTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
    }

    @Override
    public int compareTo(Delayed o) {
        return this.triggerTime.compareTo(((DelayItem) o).getTriggerTime());
    }

    public Long getTriggerTime() {
        return triggerTime;
    }

    public String getTaskContent() {
        return taskContent;
    }
}
spring延迟任务

@Scheduled也可以实现延迟执行

@Component
public class ScheduleJobs {
    @Scheduled(fixedDelay = 2 * 1000)
    public void fixedDelayJob() throws InterruptedException {
        System.out.println("任务执行,时间:" + LocalDateTime.now());
    }
}
netty延迟任务
@Slf4j
public class NettyHashedWheelTimerDemo {

    public static void main(String[] args) {
        HashedWheelTimer timer = new HashedWheelTimer(100, TimeUnit.MILLISECONDS, 8);
        timer.start();

        log.info("提交延迟任务");
        timer.newTimeout(timeout -> log.info("执行延迟任务"), 5, TimeUnit.SECONDS);
    }

}

相比上面几种延迟队列,netty在算法上做了改变,使用定时轮实现的,定时轮其实就是一种环型的数据结构,可以把它想象成一个时钟,分成了许多格子,每个格子代表一定的时间,在这个格子上用一个链表来保存要执行的超时任务,同时有一个指针一格一格的走,走到那个格子时就执行格子对应的延迟任务,如下图所示:
在这里插入图片描述

时间轮定时器最大的优势就是,任务的新增和取消都是 O(1) 时间复杂度,而且只需要一个线程就可以驱动时间轮进行工作。

上述方式的几种场景都有一些缺点

  1. 占用jvm内存,数据量大的时候可能会导致OOM
  2. 机器重启,内存中的延迟队列丢失
  3. 解决分布式部署的问题

我可以的的解决办法

  1. 来任务后将数据存入mysql之类的数据库中,只把最近要发生的任务拉取出来放入延迟队列。
  2. 分布式环境,可以增加分布式锁,只让一个服务实例去加载延迟任务
Redis延迟队列
  • 键过期通知

    默认情况下 Redis 服务器端是不开启键空间通知的,需要我们通过 config set notify-keyspace-events Ex 的命令手动开启,开启键空间通知后,我们就可以拿到每个键值过期的事件,我们利用这个机制实现了给每个人开启一个定时任务的功能,实现代码如下:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPubSub;
import utils.JedisUtils;

public class TaskExample {
    public static final String _TOPIC = "__keyevent@0__:expired"; // 订阅频道名称
    public static void main(String[] args) {
        Jedis jedis = JedisUtils.getJedis();
        // 执行定时任务
        doTask(jedis);
    }

    /**
     * 订阅过期消息,执行定时任务
     * @param jedis Redis 客户端
     */
    public static void doTask(Jedis jedis) {
        // 订阅过期消息
        jedis.psubscribe(new JedisPubSub() {
            @Override
            public void onPMessage(String pattern, String channel, String message) {
                // 接收到消息,执行定时任务
                System.out.println("收到消息:" + message);
            }
        }, _TOPIC);
    }
}

这种方式也有一个弊端,就是键值过期的时候,接受服务正好挂了,会有任务丢失

  • redis第二种任务方式是:通过 zset 数据判断

redis的zset数据结构中的每个元素都有一个分数score和一个值value,我们可以将任务的执行时间戳作为score,将任务数据作为value,将任务插入到zset中,然后在开启一个查询,消费查询出来的任务,也可以使用别人封装好的工具Redisson

<dependency>
  <groupId>org.redisson</groupId>
  <artifactId>redisson</artifactId>
  <version>3.13.1</version>
</dependency>
RabbitMQ的延迟任务
  1. 可以将正常队列设置一个过期时间,设置路由规则,过期后路由到指定队列中去消费

在这里插入图片描述

  1. 使用延迟消息插件

RabbitMQ官方推出的插件,原生支持延迟消息的功能。其原理是设计了一种支持延迟消息功能的交换机,当消息投递到交换机后可以暂存一定时间,到期后再投递到队列。

本地RabbitMQ官网下载rabbitmq_delayer_message_exchange插件地址:

https://www.rabbitmq.com/community-plugins

参考

延迟任务 https://mp.weixin.qq.com/s/aghAzOxPOVOdpSLvTBhWHw

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

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

相关文章

Charles证书的设置抓HTTPS数据包

文章目录 1.安装软件2.安装证书3.配置SSL Proxying Settings4.配置Proxy Settings5.配置浏览器流量走代理模式6.抓包效果 每次换新工作都会重新安装/配置一次Charles抓包工具&#xff0c;每次都要倒腾很久&#xff0c;配置流程不复杂&#xff0c;就是时间一久容易忘记&#xff…

下发预警处理通知,记录处理意见;错误预警修正的智慧油站开源了

AI视频监控平台简介 AI视频监控平台是一款功能强大且简单易用的实时算法视频监控系统。它的愿景是最底层打通各大芯片厂商相互间的壁垒&#xff0c;省去繁琐重复的适配流程&#xff0c;实现芯片、算法、应用的全流程组合&#xff0c;从而大大减少企业级应用约95%的开发成本。用…

海康威视 Vision Master 深度学习模块

Vision Master 深度学习模块 1. 图像分割2. 字符训练3. 目标检测4. 图像分类、图像检索 1. 图像分割 2. 字符训练 3. 目标检测 4. 图像分类、图像检索

Zilliz Cloud✖️ Ivy.ai:构建 GenAI 驱动的聊天业务

“可靠性、可扩展性和性能都很棒。而且我们可以外包所有这些管理工作&#xff0c;不必担心服务器故障&#xff0c;这有助于我们将资源投入到产品开发和创新上&#xff0c;这真正使得我们的业务与众不同。” ——Michal Oglodek&#xff0c; Ivy.ai CTO 关于Ivy.ai Ivy.ai&am…

AI剪辑短视频以及账号管理矩阵工具系统搭建开发

目录 前言 一、系统有哪些功能&#xff1f; 二、怎么开发 前言 通过AI剪辑短视频以及生成短视频&#xff0c;以及对自媒体账号的管理功能的功能进行开发。这款系统能够批量混合剪辑视频然后一键发布到绑定好的自媒体账号里面。 一、系统有哪些功能&#xff1f; 1.AI智能文…

Django中的超级管理员相关操作

超级管理员操作 场景描述添加超级管理员删除超级管理员更改超级管理员名称 场景描述 在进行管理员操作的时候&#xff0c;密码忘记&#xff0c;导致超级管理员无法使用&#xff0c;因此网上搜索相关操作&#xff0c;进行总结记录 相关操作都是在控制台完成 Terminal 添加超级管…

【Vulnhub靶机tomato渗透】

第一步&#xff1a;端口扫描 我使用的是webrobot 访问这个ip&#xff0c;就是它了 第二步&#xff1a;目录扫描 打开kali使用dirb命令扫描http://192.168.189.154下的目录 dirb http://192.168.189.154扫描到目录。 第三步&#xff1a;访问目录地址 看到有几个php的文件 第…

计算机组成原理--计算机系统概论

目的 将了解计算机的组成、工作原理及应用&#xff0c;掌握各组成部分之间的联系&#xff0c;包括总线、存储器、输入输出系统以及CPU的内部结构和功能。将对计算机体系结构有较好的理解&#xff0c;并具备一定的问题分析和解决能力。 第1章 绪论 计算机的分类计算机的发展简…

在Linux命令行中检查固件版本的7种方法

当前有几种方法可以检查 Linux上的固件或 BIOS 版本&#xff0c;这有助于解决硬件问题&#xff0c;对于保持系统安全和最新至关重要。 在本文中&#xff0c;我们将了解获取系统固件版本的工具和命令&#xff0c;这些固件版本与 BIOS、UEFI 或设备特定的固件有关。每种方法都提…

重生奇迹MU 三位公认的全能职业

今天我们来讨论游戏中公认的三个全能职业&#xff0c;看看它们中的哪一个更值得被称为“全能”。 魔武双修的魔剑士 魔剑士是游戏中最古老也是最受欢迎的特殊职业之一。一个重要的原因是它独特的魔武双修玩法&#xff0c;玩家们喜欢它。魔剑士不仅可以像剑士一样手持双刃&…

【leetcode中】螺旋矩阵2

1.题目描述 . - 力扣&#xff08;LeetCode&#xff09; 给你一个正整数 n &#xff0c;生成一个包含 1 到 n2 所有元素&#xff0c;且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。 示例 1&#xff1a; 输入&#xff1a;n 3 输出&#xff1a;[[1,2,3],[8,9,4],[7,6,…

Java_微服务

首先介绍一下单体架构与微服务架构&#xff1a; 单体架构&#xff1a; 微服务&#xff1a; SpringCloud&#xff1a; 版本&#xff1a; 标黑部分为目前企业使用最多的版本&#xff0c;因为它支持jdk8、jdk11&#xff0c;下面使用SpringCloud也会使用这个版本。 服务拆分&…

springboot校园商店配送系统-计算机毕业设计源码68448

摘要 本文详细阐述了基于Spring Boot框架的校园商店配送系统的设计与实现过程。该系统针对校园内的用户需求&#xff0c;整合了用户注册与登录、商品浏览与购买、订单管理、配送追踪、用户反馈收集以及后台管理等功能&#xff0c;为校园内的普通用户、商家、配送员和管理员提供…

今年考研报名时间确定了!(内涵西电考研报名流程)

虽然初试时间还没有得到正式官宣&#xff0c;但是再过1个多月&#xff0c;考研人们最近的一件大事——预报名就要来啦&#xff01; ⏰预报名时间 9月24日至9月27日&#xff0c;每天9:00—22:00&#xff1b; ⏰正式报名时间 10月8日至10月25日&#xff0c;每天9:00—22:00。 …

数据开发/数仓工程师上手指南(五)CDM-DIM层搭建规范及流程

前言 在上篇文章的进度和基础之上&#xff0c;我们已经算是构建好了ODS数据引入层&#xff0c;ODS这一层构建的比较简单&#xff0c;没有很多限制规范&#xff0c;但是CDM数据公共层可以算得上是数据仓库的主题&#xff0c;之前我们也将DWD数据明细层、DIM数据维度层和DWS公共…

【C++标准库】模拟实现string类(深浅拷贝问题)

模拟实现string类 一.命名空间与类成员变量二.构造函数1.无参&#xff08;默认&#xff09;构造2.有参构造3.兼容无参和有参构造4.拷贝构造1.传统写法2.现代写法 三.析构函数四.string类对象的容量操作1.size2.capacity3.clear4.empty5.reserve6.resize 五.string类对象的访问及…

Redis学习[4] ——Redis集群

五、Redis 集群 5.1 什么是Redis集群&#xff1f; 如何提供一个高可用的Redis服务&#xff1f; —— 构建Redis集群 单服务器Redis由于数据都是存储在一台服务器&#xff0c;如果这台服务器出现宕机或者故障&#xff0c;可能会导致服务不可用甚至数据丢失。 要避免这种单点…

C#使用NPOI进行Excel和Word文件处理(一)

文章目录 前言文件大小性能NPOI 的优势示例代码性能优化建议总结Github 地址链接导出效果 前言 NPOI 是一个非常流行的用于在 .NET 环境中操作 Office 文件&#xff08;包括 Excel 文件&#xff09;的开源库。它的功能非常强大&#xff0c;但性能和文件大小问题可能因具体的使…

“八股文”面试题:是招聘程序员的金科玉律?

引言 随着互联网的发展&#xff0c;现代企业对程序员的需求日益增加。在招聘过程中&#xff0c;许多公司采用了“八股文”式的面试题目来筛选候选人。这些题目往往涵盖了算法、数据结构、系统设计等方面的基础知识。然而&#xff0c;对于“八股文”在实际工作中的作用&#xf…

安泰高压放大器在材料极化中的应用有哪些

高压放大器在材料极化中具有重要的应用&#xff0c;这方面是通过在材料中施加高电压来实现的。下面我们将探讨高压放大器在材料极化领域的具体应用&#xff0c;以及其在材料科学和工程中的重要性。 首先&#xff0c;让我们了解一下材料极化的基本概念。材料的极化是指在外加电场…