定时任务-xxl-job

news2024/11/16 21:54:13

一. 为什么定时任务可以定时执行

定时任务可以定时执行的原理是通过操作系统提供的定时器实现的。

以下是定时任务能够准时执行的基本原理和相关技术:
操作系统的调度器: 操作系统(如Linux、Windows等)内部都有一个调度器,负责管理和调度各种进程和任务。这个调度器通常基于时间片(time slice)或者其他调度算法来分配CPU时间给不同的任务。
定时器和时钟: 操作系统会维护一个时钟系统,它通常是一个硬件计时器或者软件计时器,用于定期触发中断或事件。基于这些时钟,操作系统能够准确追踪时间,并在指定的时刻触发特定的任务。
定时任务的注册和管理: 在操作系统或者特定的任务调度器中,可以注册和管理定时任务。这些任务通常由操作系统或者相关的服务来执行,并在指定的时间点或时间间隔内触发执行。
精确时间的管理: 现代操作系统能够提供比较精确的时间管理,如毫秒级或者更高的精度,这使得定时任务可以按照预期的时间间隔或者具体的时间点执行。
持久化和可靠性: 对于需要持久化的定时任务,操作系统或者相关的任务调度器通常会保证在系统重启后能够恢复原有的调度状态,确保定时任务不会因为系统重启而中断。

二. 为什么Cron表达式可以定时执行

Cron表达式可以定时执行底层也是基于操作系统的定时器的机制。在常见的计算机操作系统中,都提供了一种定时器机制,可以设置定时器来触发某个操作或执行某个任务。在我们在系统中设置了一个Cron任务后,Cron服务会工具Cron表达式计算出任务下一次应该执行的时间点,并将这个时间点与当前时间点进行比较,如果当前时间点已经超过了任务的执行时间点,那么Cron服务会立即执行该任务;否则Cron服务会将任务的执行时间点记录下来,并在这个时间点到来时再执行任务。

在 Unix/Linux 系统中,Cron 服务通常是通过一个名为 cron 的系统服务来实现的。这个服务会周期性地检查系统中已经配置好的 crontab 文件,根据其中的配置信息来决定哪些任务应该被执行。

crontab 文件中包含了多条定时任务的配置信息,其中每条任务都由五个时间字段和一个命令行指令组成。这五个时间字段分别表示分钟、小时、日期、月份和星期几,cron 会根据这些时间信息来判断任务何时应该被执行。当定时器达到指定时间时,cron 会根据 crontab 文件中的配置信息,启动相应的命令行指令来执行任务。这样,定时任务就可以按照预定的时间定时执行了。

三. Java中实现定时任务的方式

1. java中原生特性(JDK自带的功能)实现定时任务:

Timer类和TimerTask类: Timer类是Java SE5之前的一个定时器工具类,可用于执行定时任务。TimerTask类则表示一个可调度的任务,通常通过继承该类来实现自己的任务,然后使用Timer.schedule()方法来安排任务的执行时间。

ScheduledExecutorService类: ScheduledExecutorService是Java SE5中新增的一个定时任务执行器,它可以比Timer更精准地执行任务,并支持多个任务并发执行。通过调用ScheduledExecutorService.schedule(或ScheduledExecutorService.scheduleAtFixedRate()方法来安排任务的执行时间。

DelayQueue: DelayQueue是一个带有延迟时间的无界阻塞队列,它的元素必须实现Delayed接口。当从DelayQueue中取出一个元素时,如果其延迟时间还未到达,则会阻塞等待,直到延迟时间到达。因此,我们可以通过将任务封装成实现Delaved接口的元素,将其放入DelayQueue中再使用一个线程不断地从DelayQueue中取出元素并执行任务,从而实现定时任务的调度。

2. 需要引入第三方框架实现定时任务方式:

Spring的@Scheduled注解: Spring框架提供了一个方便的定时任务调度功能,可以使用@Scheduled注解来实现定时任务。通过在需要执行定时任务的方法上加上@Scheduled注解,并指定执行的时间间隔即可。

Quartz框架: Quartz是一个流行的开源任务调度框架,它支持任务的并发执行和动态调度。通过创建JobDetail和Trigger对象,并将它们交给Scheduler进行调度来实现定时任务。

xxl-job: xxl-job是一款分布式定时任务调度平台,可以实现各种类型的定时任务调度,如定时执行Java代码、调用HTTP接口、执行Shel脚本等。xxl-job采用分布式架构,支持集群部署,可以满足高并发、大数据量的任务调度需求。

Elastic-Job: Elastic-Job是一款分布式任务调度框架,可以实现各种类型的定时任务调度,如简单任务、数据流任务、脚本任务、Spring
Bean任务等。Elastic-Job提供了丰富的任务调度策略可以通过配置cron表达式、固定间隔等方式实现定时任务调度。Elastic-Job支持分布式部署,提供了高可用性和灵活的扩展性,可以满足高并发、大数据量的任务调度需求,

3. java中原生特性(JDK自带的功能)实现定时任务与引入第三方框架实现定时任务区别:

java中原生特性实现定时任务,相比于xxl-job这种定时任务调度框架来说,原生特性实现起来简单,不用依赖第三方的调度框架和类库。方案更加轻量级。缺点是原生特性方案都是基于JVM内存的,需要把定时任务提前放进去,如果数据量太大的话,可能会导致OOM的问题;另外,基于JVM内存的方案,一旦机器重启了,里面的数据就都没有了,所以一般都需要配合数据库的持久化一起用,并且在应用启动的时候也需要做重新加载。

四. 实现一个定时任务,可以用什么数据结构和算法

1.小顶堆:可以使用小顶堆来管理定时任务,其中每个事件包含触发时间戳和要执行的任务信息。最先要触发的任务处于堆的根部,这样可以高效地找到最近触发的定时事件,并在触发时执行相应的任务。

小顶堆(Min Heap)是一种特殊的二又堆数据结构。对于堆中的任意节点i,其父节点的值小于等于节点i的值。换句话说,堆中的最小值总是位于堆的根节点上。
在定时器的实现中,每个定时事件可以表示为一个包含触发时间戳的数据结构。从堆顶不断取出需要执行的定时任务即可。在这里插入图片描述

2.时间轮算法:时间轮算法是一种时间管理算法,可以高效地处理定时任务。是一种用于处理定时任务和调度的常见算法。它把时间划分成若干个时间槽,并使用循环队列来存储在每个时间槽上触发的任务,从而避免了遍历整个定时事件集合的开销。
时间轮(TimingWheel)是一个 存储定时任务的环形队列,底层采用数组实现,数组中的每个元素可以存放一个定时任务列表(TimerTaskList)。TimerTaskList 是一个环形的双向链表,链表中的每一项表示的都是定时任务项(TimerTaskEntry),其中封装了真正的定时任务 TimerTask。

简单时间轮算法:
时间轮算法主要需要定义一个时间轮盘,在一个时间轮盘中划分出多个槽位,每个槽位表示一个时间段,这个段可以是秒级、分钟级、小时级等等。如以下就是把一个时间轮分为了60个时间槽,每一个槽代表一秒钟。

在这里插入图片描述
当我们有定时任务需要执行的时候,就把他们挂在到这些槽位中,这个任务将要在哪个槽位中执行,就把他挂在到哪个槽位的链表上。比如当前如果是0秒,那么要3秒后执行,那就挂在槽位为3的那个位置上。
缺点:这种时间轮存在一个问题,就是分了多少槽位,就只支持多少以内定时。

简单时间轮加round:
在时间轮中增加一个round的标识,标识运行的圈数,比如上面的60s的时间轮,如果我要200s之后运行,那么我在设置这个任务的时候,就把他的round设置为200/60=3,然后再把它放到200%60=20的这个槽位上。
有了这个round之后,每一次current移动到某个槽位时,检查任务的round是不是为0,如果不为0,则减一。这样时间轮转到第三圈时,round的值会变成0,再第四运行到current=20的时候,发现round=0了,那么就可以执行这个任务了。
缺点:round的检查过程,需要把所有任务都遍历一遍,效率不高。
在这里插入图片描述

分层时间轮:
专为大批量定时任务管理而生。比如要支持触发时间是一年的精度为秒级别的时间轮,如果单纯的用一个秒级的时间轮:3652460*60 这都三千多万个时间格了,造成大量资源开销。而分层的话,那么可分为四个层次,天级别的时间轮,小时级时间轮,分钟级时间轮,秒级时间轮,他们的时间格数分别为365,24,60,60,总时间格数只有365+24+60+60=509个。这样解决了上面两种时间轮的缺点。
在这里插入图片描述

3.链表(用的比较少):链表可以用于管理定时事件,每个节点包含触发时间戳和任务信息。链表中的节点按照触发时间戳从小到大排序,通过遍历链表,可以找到最近触发的定时事件并执行任务。

五.xxl-job怎么保证任务只会触发一次

xxl-job 作为一个定时任务调度工具,需要确保同一时间内同一任务只会在一个执行器上执行。这个特性对于避免任务的重复执行非常关键,特别是在分布式环境中,多个执行器实例可能同时运行相同的任务。这个特性被xxl-job描述为“调度一致性”,“调度中心”通过DB锁保证集群分布式调度的一致性,一次任务调度只会触发一次执行。

几个关键点:
任务调度器: xxl-job 的调度器负责按照设定的调度策略(如 cron表达式)定时触发任务执行。调度器确保在预定的时间点触发任务,避免任务重复触发。
执行器与任务执行状态管理: 执行器是实际执行任务逻辑的组件,它负责执行具体的任务代码。xxl-job会在任务执行前记录任务的执行状态,并在执行完成后更新任务状态,以确保同一个任务实例不会重复执行。
任务幂等性: 开发者需要在编写任务逻辑时考虑任务的幂等性,确保任务的多次执行不会产生错误结果或者重复操作。xxl-job 并未提供特定的JobScheduleHelper 类或方法来保证任务只会触发一次,而是通过任务的设计和调度管理来实现这一目标。
调度中心管理任务触发: xxl-job 的核心组件是调度中心,它负责管理注册的所有任务及其调度配置(如CRON表达式)。调度中心根据任务的执行时间点和配置,决定何时触发任务的执行。调度中心在XXL-JOB中负责管理所有任务的调度,当到达指定的执行时间点,调度中心会选择一个执行器实例来执行任务。
数据库锁确保任务唯一执行: 为了确保任务在同一时间点只会被触发一次执行,xxl-job 使用了数据库锁机制。具体来说,当调度中心准备触发某个任务时,它会尝试获取数据库中的锁。这些锁可以是行级锁或表级锁,用于控制对任务执行状态的并发访问。
JobScheduleHelper 协调任务调度: JobScheduleHelper 是 xxl-job 中负责协调任务调度逻辑的组件之一。它利用数据库锁基于数据的悲观锁实现的一个加锁过程,确保同一时间点只有一个执行器实例能够获取并执行特定任务。其他执行器实例在获取锁失败时会等待或重试,以避免重复执行。

六.xxl-job支持分片任务的实现原理:

分片任务非常适用于处理大数据的任务,其实就是可以将一个大任务划分为多个子任务并行执行来提高效率。

分片任务的实现原理主要包含以下几个核心步骤:
任务分配: 当一个分片任务被触发时,调度器会根据任务的分片参数决定需要多少个执行器参与任务。每个执行器或执行线程会接收到一个分片索引(shard index)和分片总数(shard total)。
分片参数: 分片索引(从0开始)标识了当前执行器处理的是哪一部分数据。分片总数告诉执行器总共有多少个分片。
并行执行: 每个执行器根据分配到的分片索引并行执行其任务。例如,如果一个任务被分为10个片,那么每个执行器可能负责处理10%的数据。
处理逻辑: 开发者在任务实现时需要根据分片索引和分片总数来调整处理逻辑,确保每个分片处理正确的数据段。
结果汇总: 分片执行完毕后,各个执行器的执行结果可以被独立处理,或者可以通过某种机制进行结果的汇总和整合。

当一个任务被分片任务调度的时候,会带着shardlndex和shardTotal两个参数过来,我们就可以解析这两个参数进行分片执行。
例子如下:

public ReturnT<String>orderTime0utExecute(){
		int shardIndex=XxlJobHelper.getShardIndex();
		int shardTotal =XxlJobHelper.getShardTotal();
		if(userId %shardTotal == shardIndex){
			// 执行任务
			System.out.println("执行任务:用户"+ userId);
		}else {
			//不执行任务
			System.out.println("用户"+userId +" 不执行任务");
		}
}

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

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

相关文章

TortoiseGit小乌龟在gitlab配置ssh免密

1. 生成ssh密钥(默认在~/.ssh路径生产&#xff0c;id_rsa和id_rsa.pub) ssh-keygen -t rsa -b 4096 -C "xxxqq.com"2. 打开gitlab&#xff0c;在搜索栏搜索ssh&#xff0c;找到SSH Keys&#xff0c;然后添加id_rsa.pub公钥的内容到网页&#xff0c;保存。 3. 打开To…

如何将PostgreSQL的数据实时迁移到SelectDB?

PostgreSQL 作为一个开源且功能强大的关系型数据库管理系统&#xff0c;在 OLTP 系统中得到了广泛应用。很多企业利用其卓越的性能和灵活的架构&#xff0c;应对高并发事务、快速响应等需求。 然而对于 OLAP 场景&#xff0c;PostgreSQL 可能并不是最佳选择。 为了实现庞大规…

数据结构(其三)--栈与队列

目录 5.栈 5.1 栈的基本操作 5.2 各种栈 &#xff08;1&#xff09;.顺序栈 i.普通顺序栈 ii.共享栈 iii.关于销毁 &#xff08;2&#xff09;.链栈 6.队列 6.1 队列的基本操作 6.2 各种队列 &#xff08;1&#xff09;.循环队列 i.代码 ii.另外一种写法 &#xff08…

[Latex美化]-表格加底色,添加灰色美化表格,便于阅读

1 导入库 \usepackage{xcolor} \usepackage{colortbl, booktabs} 2 插入指令&#xff08;指定行前&#xff09; \rowcolor{gray!30} 具体代码如下 效果如下

循环神经网络RNN介绍

文章目录 1、学习介绍2、RNN的基本结构2.1、图例2.2、公式2.3、公式计算示例2.3.1、给定参数2.3.2、时间步计算 3、序列依赖与梯度消失/爆炸3.1、序列依赖3.2、梯度消失与爆炸3.3、总结 4、传统的前馈神经网络4.1、结构4.2、工作原理4.3、特点4.4、局限性 5、CNN与RNN的关系5.1…

【建造者模式】全面解析与最佳实践:打造复杂对象的蓝图(构建复杂对象的艺术)

文章目录 Java中的建造者模式&#xff1a;全面解析与最佳实践1. 引言2. 建造者模式概念定义与用途适用场景解决的问题 3. 建造者模式原理主要角色解释工作流程UML图和时序图 4. 建造者模式在Java中的实现逐步构建示例程序1. 创建抽象建造者类2. 实现具体建造者类3. 设计产品类4…

如何在厂商软件不提供二次开发资源的情况下实现LabVIEW开发

在遇到厂商提供的软件不支持二次开发资源时&#xff0c;如果需要使用LabVIEW进行开发&#xff0c;通常面临以下几个挑战&#xff1a;设备通讯接口封闭、协议不公开、厂商技术支持有限等。这些问题需要综合考虑并制定解决方案&#xff0c;以下是详细的分析&#xff1a; 1. 了解原…

权限模块开发+权限与角色关联(完整CRUD)

文章目录 &#x1f31e; Sun Frame&#xff1a;SpringBoot 的轻量级开发框架&#xff08;个人开源项目推荐&#xff09;&#x1f31f; 亮点功能&#x1f4e6; spring cloud模块概览常用工具 &#x1f517; 更多信息1.easycode生成代码1.配置2.AuthPermissionDao.java剪切到mapp…

SharpLab:.Net反编译工具,方便实时查看反编译后的代码!

C#提供了很多高级语法&#xff0c;很多都是语法糖。这些语法糖对于初学者来说&#xff0c;很多无法理解。 下面推荐一个开源项目&#xff0c;它能够让我们&#xff0c;实时查看编译过程、生成的中间语言&#xff08;IL&#xff09;以及反编译后的代码。 01 项目简介 SharpLa…

C语言 ——深入理解指针(2)

目录 1. 数组名的理解2. 二级指针3. 指针数组4. 字符指针变量5. 数组指针变量6. 函数指针变量7. 函数指针数组 1. 数组名的理解 这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址&#xff0c;但是其实数组名本来就是地址&#xff0c;而且是数组首元素的地址&#x…

TabLayout使用以及自定义tab标签

<?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.com/apk/res-auto"xmlns:tool…

YoloV10 论文翻译(Real-Time End-to-End Object Detection)

​摘要 近年来&#xff0c;YOLO因其在计算成本与检测性能之间实现了有效平衡&#xff0c;已成为实时目标检测领域的主流范式。研究人员对YOLO的架构设计、优化目标、数据增强策略等方面进行了探索&#xff0c;并取得了显著进展。然而&#xff0c;YOLO对非极大值抑制&#xff0…

01【功能项目】之【主角射线点击导航】

首先创建一个Unity3D的项目 打开资源商店添加一个人物模型 选择一个免费资源主角添加至项目中 在unity中打开后点击下载包 点击导入包 导入成功后会出现在资源包Assets下 右键创建地面 设置地面尺寸 创建一个材料方便给地面调配颜色 选择材料的颜色 将材质拖拽给地面组为组件 将…

double类型 精度丢失的问题

前言 精度丢失的问题是在其他计算机语言中也都会出现&#xff0c;float和double类型的数据在执行二进制浮点运算的时候&#xff0c;并没有提供完全精确的结果。产生误差不在于数的大小&#xff0c;而是因为数的精度。 一、double进行运算时,经常出现精度丢失 0.10.2使用计算…

QTableView使用示例-Qt模型视图代理(Model-View-Delegate)使用示例

模型视图委托&#xff08;MVD&#xff09;是Qt中特有的设计模式&#xff0c;类似MVC设计模式&#xff0c;将MVC设计模式中的Controller当做MVD中的Delegate&#xff0c;两者的概念基本相同。不同的是委托不是独立存在&#xff0c;而是包含在视图里面。 模型视图委托设计模式中&…

#71结构体案例2(三国游戏,冒泡排序)

效果&#xff1a; 代码&#xff1a; #include <iostream> #include <string> using namespace std;//英雄结构体 struct Hero {string name;int age;string gender; };//冒泡排序 void bubbleSort(struct Hero hArray[],int len) {for(int i0;i<len-1;i){for(i…

CentOS 8 本地创建yum源

1.获取iso (有iso就可以建立本地repo) 如CentOS-8.5.2111-aarch64-dvd1.iso 2.解压iso&#xff08;mount挂载就可以吧iso解压到linux某一目录中&#xff09; mkdir /mnt/cdrom mount -o loop ./CentOS-Stream-8-aarch64-20220913-dvd1.iso /mnt/cdrom ls /mnt/cdrom 3.编…

奇偶函数的性质及运算

目录 定义 注意 特征 运算 拓展 定义 设函数f(x)的定义域D&#xff1b; 如果对于函数定义域D内的任意一个x&#xff0c;都有f(-x)&#xff0d;f&#xff08;x&#xff09;&#xff0c;那么函数f&#xff08;x&#xff09;就叫做奇函数。如果对于函数定义域D内的任意一个x…

【前端】 如何在 Vue.js 中使用 Mock 数据:教程与技巧

如何在 Vue.js 中使用 Mock 数据&#xff1a;教程与技巧 在开发过程中&#xff0c;为了测试和开发前端功能&#xff0c;你常常需要用到模拟&#xff08;mock&#xff09;数据。Vue.js 提供了灵活的方式来处理数据请求和更新&#xff0c;但在没有真实后端的情况下&#xff0c;我…

在 VueJS 中使用事件委托处理点击事件(事件委托,vue事件委托,什么是事件委托,什么是vue的事件委托)

前言 在开发 Vue 项目时&#xff0c;我们经常需要处理大量的点击事件。为每个可点击的元素单独添加事件监听器不仅会增加代码的复杂度&#xff0c;还会降低性能。事件委托是一种有效的优化方式&#xff0c;它可以显著减少事件监听器的数量&#xff0c;提高代码的可维护性和执行…