手撸XXL-JOB(一)——定时任务的执行

SpringBoot执行定时任务

对于定时任务的执行,SpringBoot提供了三种创建方式:
1)基于注解(@Scheduled)
2)基于接口(SchedulingConfigurer)
3)基于注解设定多线程定时任务

基于Scheduled注解

首先我们创建一个SpringBoot项目,然后引入spring-boot-starter-web依赖,在启动类上添加EnableScheduling注解开启定时任务管理。

package com.yang.demo1;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;@SpringBootApplication
@EnableScheduling
public class ScheduledDemoApplication {public static void main(String[] args) {SpringApplication.run(ScheduledDemoApplication.class, args);}
}

然后我们创建一个定时任务,并使用Scheduled注解

package com.yang.demo1;import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;import java.text.SimpleDateFormat;
import java.util.Date;@Component
public class DemoTask {@Scheduled(cron = "0/5 * * * * ?") // 每5秒执行一次public void execute() {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("hello world: " + df.format(new Date()));}
}

启动项目,执行结果如下所示,每隔5秒,便会执行一次定时任务。
image.png
Scheduled注解类的源码如下:

package org.springframework.scheduling.annotation;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
public @interface Scheduled {String CRON_DISABLED = "-";String cron() default "";String zone() default "";long fixedDelay() default -1L;String fixedDelayString() default "";long fixedRate() default -1L;String fixedRateString() default "";long initialDelay() default -1L;String initialDelayString() default "";
}

除了刚才代码中使用到的cron参数,我们还可以使用fixedDelay和fixedRate等参数。fixedDelay和fixedRate很相似,但又略有不同,其中fixedDelay表示在某次任务执行完毕后,间隔fixedDelay的时间再执行,而fixedRate表示在某次任务执行开始后,间隔fixedRate的时间再执行。
我们对这两个参数,添加对应的测试方法:

  @Scheduled(fixedDelay = 5000)public void executeFixedDelay() {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("executeFixedDelay开始执行了==========" + df.format(new Date()));try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}@Scheduled(fixedRate = 5000)public void executeFixedRate() {SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println("executeFixedRate开始执行了==========" + df.format(new Date()));try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}}

启动项目,执行结果如下。我们可以看到,executeFixedDelay在任务执行完毕后,间隔5秒才执行下一个任务,也就是说,两个任务之间间隔7秒,而executeFixedRate在任务执行开始后,间隔5秒执行下一个任务,也就是两个任务之间间隔5秒。综上所示,fixedDelay和fixedRate之间的区别,其实就在于计算两个任务执行间隔时,需不需要考虑任务的执行时长。
image.png

基于SchedulingConfigurer接口

首先我们在数据库中创建t_cron表,并添加数据:

DROP TABLE IF EXISTS t_cron;
CREATE TABLE t_cron  (cron_id VARCHAR(30) NOT NULL PRIMARY KEY,cron VARCHAR(30) NOT NULL  
);INSERT INTO t_cron VALUES ('1', '0/5 * * * * ?');

然后修改pom.xml,加上数据库的相关依赖:

  <dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.3</version></dependency>

修改配置文件:

spring:datasource:username: rootpassword: 3fa4d180url: jdbc:mysql://localhost:3306/test01?useSSL=false&serverTimezone=UTCdriver-class-name: com.mysql.cj.jdbc.Driver
mybatis-plus:configuration:log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

创建对应的mapper:

package com.yang.demo1.mapper;import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;@Mapper
public interface CronMapper {@Select("select cron from t_cron limit 1")String getCron();
}

然后,我们编写定时任务,通过读取我们在数据库设置好的执行周期,来执行定时任务,代码如下:

package com.yang.demo1;import com.yang.demo1.mapper.CronMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;import java.time.LocalDateTime;@Configuration
@EnableScheduling
public class DynamicScheduleConfigurer implements SchedulingConfigurer {@Autowiredprivate CronMapper cronMapper;@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.addTriggerTask(() -> execute(),triggerContext -> {String cron = cronMapper.getCron();if (StringUtils.isEmpty(cron)) {throw new RuntimeException("cron 格式有误");}return new CronTrigger(cron).nextExecutionTime(triggerContext);});}private void execute() {System.out.println("hello world:" + new Date());}
}

执行结果如下所示,一开始的cron是每5秒执行一次,后来我们修改cron,改为10秒执行一次,此时任务的执行频率,也随之我们数据库的修改动态地进行了调整。
image.png

EnableAsync注解

对于Scheduled,默认为单线程,当开启多个任务时,任务地执行实际会受到上一个任务执行时间地影响,所以需要使用Async注解,通过该注解开启多线程使任务之间不会相互影响。

ScheduledExecutorService执行定时任务

SpringBoot执行定时任务很简单,但是如果我们不使用SpringBoot,又该如何启动定时任务?这个时候,我们就可以使用ScheduledExecutorService接口,这个接口用于在一些预定义的延迟之后运行任务或定期运行任务。我们可以通过Executors类的工厂方法实例化ScheduledExecutorService,如下:

        ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();

在ScheduledExecutorService接口中,有三个主要方法:
1)schedule:允许在指定的延迟后执行一次任务。
2)scheduleAtFixedRate:允许在指定的初始延迟后执行任务,然后以一定的周期重复执行,其中period参数用于指定两个任务的开始时间之间的间隔时间,因此任务执行的频率是固定的。
3)scheduleWithFixedDelay:类似于scheduleAtFixedRate,它也重复执行给定的任务,单period参数用于指定前一个任务的结束和下一个任务的开始之间的间隔时间,也就是指定下一个任务延时多久后才执行,执行频率可能会有所不同,具体取决于执行任务给定任务所需的时间。

schedule方法
package com.yang.demo2;import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;public class ScheduledExecutorServiceMain {public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);scheduledExecutorService.schedule(() -> {System.out.println("Hello World:" + new Date());}, 1, TimeUnit.SECONDS);try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}scheduledExecutorService.shutdown();try {if (!scheduledExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {scheduledExecutorService.shutdownNow();}} catch (InterruptedException e) {e.printStackTrace();}}
}

结果如下:在延迟一秒后,开始执行任务,且只执行一次。
image.png

scheduleAtFixRate

当我们需要在固定延迟后,定期执行任务时,可以使用scheduleAtFixedRate方法,如下所示,每隔2秒执行相同的任务

public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1);scheduledExecutorService.scheduleAtFixedRate(() -> {System.out.println("Hello World:" + new Date());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}, 0, 2, TimeUnit.SECONDS);try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}scheduledExecutorService.shutdown();try {if (!scheduledExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {scheduledExecutorService.shutdownNow();}} catch (InterruptedException e) {e.printStackTrace();}}

结果如下:
image.png
如果任务执行时间比间隔时间长,那么scheduledExecutorService将等待当前任务执行完毕后再开始执行下一个任务,我们修改代码如下:

 ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);scheduledExecutorService.scheduleAtFixedRate(() -> {System.out.println("Hello World:" + new Date());try {Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}}, 0, 2, TimeUnit.SECONDS);try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}scheduledExecutorService.shutdown();try {if (!scheduledExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {scheduledExecutorService.shutdownNow();}} catch (InterruptedException e) {e.printStackTrace();}

结果如下,每隔3秒执行一次任务
image.png

scheduleWithFixedDelay方法

如果任务之间必须具有固定长度的延迟,那么可以使用scheduleWithFixedDelay方法。

  public static void main(String[] args) {ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(4);scheduledExecutorService.scheduleWithFixedDelay(() -> {System.out.println("Hello World:" + new Date());try {Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}, 0, 2, TimeUnit.SECONDS);try {Thread.sleep(20000);} catch (InterruptedException e) {throw new RuntimeException(e);}scheduledExecutorService.shutdown();try {if (!scheduledExecutorService.awaitTermination(10, TimeUnit.SECONDS)) {scheduledExecutorService.shutdownNow();}} catch (InterruptedException e) {e.printStackTrace();}}

在上述代码中,任务执行时长需要1秒,然后设置的间隔时间为2秒,因此,我们可以看到,每隔任务之间,间隔3秒执行一次
image.png

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

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

相关文章

基于51单片机的冰箱控制系统设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机冰箱控制系统设计( proteus仿真程序设计报告原理图讲解视频&#xff09; 基于51单片机冰箱控制系统设计 1. 主要功能&#xff1a;2. 讲解视频&#xff1a;3. 仿真4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单&&下载链接资料下载链接&#xff1a; …

【C++】学习笔记——继承_2

文章目录 十二、继承5. 继承与友元6. 继承与静态成员7. 复杂的菱形继承及菱形虚拟继承 未完待续 十二、继承 5. 继承与友元 友元关系不能继承&#xff0c;也就是说父类友元不能访问子类私有和保护成员 。除非子类也设置成友元。 6. 继承与静态成员 父类定义了 static 静态成…

pnpm:无法加载文件 C:\Users\PC\AppData\Roaming\npm\pnpm.ps1,因为在此系统上禁止运行脚本。

使用pnpm命令启动vue时报了个错&#xff1a; 解决起来也简单&#xff0c;右击开始菜单&#xff0c;用管理员身份打开终端。win11的如下图&#xff1a; win10我记得应该是PowerShell&#xff08;管理员&#xff09;&#xff0c;这样的。 打开之后执行命令&#xff1a; set-…

物联网平台之单体架构

介绍本文主要介绍平台的单体架构&#xff0c;包括各个组件之间的数据流描述以及所做的一些架构选择。在单体架构模式下&#xff0c;所有 ThingsKit 组件都在单个 Java 虚拟机 (JVM) 中启动&#xff0c;并共享相同的操作系统资源。由于 ThingsKit 是用 Java 编写的&#xff0c;因…

dnf手游攻略,新手入坑必备!

一、角色创建策略 在DNF手游中&#xff0c;角色创建是玩家初入游戏的首要步骤。为最大化游戏体验和收益&#xff0c;新手玩家通常建议创建三个角色&#xff1a;一个主账号和两个副账号。 主账号选择 主账号的选择应基于玩家个人的喜好和对职业的熟悉程度。无论选择哪个职业&a…

番外篇 | 手把手教你利用YOLOv8进行热力图可视化 | 针对视频

前言:Hello大家好,我是小哥谈。YOLOv8的热力图可视化可以帮助我们更加直观地了解模型在图像中的检测情况,同时也可以帮助我们进行模型的调试和优化。热力图是一种颜色渐变的图像,不同颜色的区域表示不同程度的关注度或者置信度。在YOLOv8中,可以通过设置阈值来控制热力图的…

电机控制杂谈——“双采样双更新模式”对模型预测控制/PI控制的提升有多大?

1.采样频率与PWM开关频率的关系 一般有以下两种采样模式。 如下图&#xff08;a&#xff09;所示&#xff0c;这种方式称之为单采单更模式&#xff0c;即在一个PWM周期内&#xff0c;采样一次&#xff0c;更新一次PWM占空比&#xff0c;在这种情况下&#xff0c;采样频率&…

小红书自动私信获客,打造个人品牌

在当今这个内容为王、社交至上的时代&#xff0c;小红书作为新兴的社交电商平台&#xff0c;凭借其独特的社区氛围和强大的种草能力&#xff0c;成为了众多KOL、商家以及个人品牌打造的首选平台。想要在小红书上脱颖而出&#xff0c;精准引流获客&#xff0c;利用自动私信功能不…

【MyBatis】 MyBatis框架下的高效数据操作:深入理解增删查改(CRUD)

文章目录 1. 环境准备2. 增加数据&#xff08;Create&#xff09;3. 查询数据&#xff08;Retrieve&#xff09;4. 更新数据&#xff08;Update&#xff09;5. 删除数据&#xff08;Delete&#xff09;6. 总结 &#x1f389;欢迎来到Java学习路线专栏~探索Java中的静态变量与实…

强化训练:day8(求最小公倍数、数组中的最⻓连续⼦序列、字⺟收集)

文章目录 前言1. 最小公倍数1.1 题目描述1.2 解题思路1.3 代码实现 2. 数组中的最⻓连续⼦序列2.1 题目描述2.2 解题思路2.3 代码实现 3. 字母收集3.1 题目描述3.2 解题思路3.3 代码实现 总结 前言 1. 最小公倍数   2. 数组中的最⻓连续⼦序列   3. 字⺟收集 1. 最小公倍数…

JavaEE之线程(5)——Java内存模型、内存可见性、volatile关键字

前言 volatile可以理解成轻量级的 synchronized&#xff0c; 它在多CPU开发中保证了共享变量的“可见性”&#xff0c;可见性我们可以理解成是&#xff1a;当一个线程修改一个共享变量时&#xff0c;另一个线程可以读到这个修改的值。由于它不会引起线程的上下文切换和调度&am…

HTML的使用(中)

文章目录 前言一、HTML表单是什么&#xff1f;二、HTML表单的使用 &#xff08;1&#xff09;<form>...</form>表单标记&#xff08;2&#xff09;<input>表单输入标记总结 前言 在许多网页平台上浏览&#xff0c;大多逃不了登录账号。此时在网页中填写的用户…

Centos 7.9 安装 tigervnc-server

环境&#xff1a;当前使用的 Centos 7.9 的光盘作为的本地源&#xff0c;或使用离线rpm包。 1 检查是否已安装 tigervnc [rootlocalhost /]# rpm -q tigervnc tigervnc-server 未安装软件包 tigervnc tigervnc-server-1.8.0-21.el7.x86_64 如果安装过卸掉 卸载: rpm -e [ro…

MYSQL DBA运维实战 SQL2

1.DML:通过SQL语句中的DML语言来实现数据的操作。 insert实现数据的插入。 update实现数据的更新。delete实现数据的删除。 插入&#xff0c;完全插入insert into 表名 values(值) 非完全插入:insert into 表名(列名&#xff0c;列名) values(值) 更新&#xff0…

RustGUI学习(iced)之小部件(十二):如何使用rule分割线部件来分割UI?

前言 本专栏是学习Rust的GUI库iced的合集,将介绍iced涉及的各个小部件分别介绍,最后会汇总为一个总的程序。 iced是RustGUI中比较强大的一个,目前处于发展中(即版本可能会改变),本专栏基于版本0.12.1. 概述 这是本专栏的第十二篇,主要讲述rule分割线部件的使用,会结合…

【计算机网络】http协议的原理与应用,以及https是如何保证安全传输的

HTTP 超文本传输协议&#xff08;英文&#xff1a;HyperText Transfer Protocol&#xff0c;缩写&#xff1a;HTTP&#xff09;是一种用于分布式、协作式和超媒体信息系统的应用层协议。HTTP是万维网的数据通信的基础。 HTTP的发展是由蒂姆伯纳斯-李于1989年在欧洲核子研究组织…

React useEffect Hook: 理解和解决组件双重渲染问题

在React中&#xff0c;useEffect可能会在组件的每次渲染后运行&#xff0c;这取决于它的依赖项。如果你发现useEffect运行了两次&#xff0c;并且你正在使用React 18或更高版本的严格模式&#xff08;Strict Mode&#xff09;&#xff0c;这可能是因为在开发模式下&#xff0c;…

轻松掌握抖音自动点赞技巧,快速吸粉

在当今这个信息爆炸的时代&#xff0c;抖音作为短视频领域的领头羊&#xff0c;不仅汇聚了庞大的用户群体&#xff0c;也成为了品牌和个人展示自我、吸引粉丝的重要平台。如何在众多内容创作者中脱颖而出&#xff0c;实现高效引流获客&#xff0c;精准推广自己的内容&#xff0…

LVS负载均衡超详细入门介绍

LVS 一、LVS入门介绍 1.1.LVS负载均衡简介 1.2.负载均衡的工作模式 1.2.1.地址转换NAT&#xff08;Network Address Translation&#xff09; 1.2.2.IP隧道TUN&#xff08;IP Tunneling&#xff09; 1.2.3.直接路由DR&#xff08;Direct Routing&#xff09; 1.3.…

ThingsBoard版本控制配合Gitee实现版本控制

1、概述 2、架构 3、导出设置 4、仓库 5、同步策略 6、扩展 7、案例 7.1、首先需要在Giitee上创建对应同步到仓库地址 ​7.2、giit仓库只能在租户层面进行配置 7.3、 配置完成后&#xff1a;检查访问权限。显示已成功验证仓库访问&#xff01;表示配置成功 7.4、添加设…