一文详解SpringBoot 定时任务(cron表达式)

news2025/4/27 16:26:49

IDE:IntelliJ IDEA 2022.2.3 x64
操作系统:win10 x64 位 家庭版
JDK: 1.8


文章目录

  • 一、如何开启一个SpringBoot定时任务?
  • 二、cron表达式详解
    • 2.1 语法格式
    • 2.2 符号解析
      • 2,2.1 通用符号: , - * /
      • 2.2.2 专有符号:?L w
    • 2.3 测试运行
  • 三、fixedRate & fixedDelay
    • 3.1 fixedRate
    • 3.2 fixedDelay
  • 四、如何异步多线程的执行SprigBoot定时任务?


提示:以下是本篇文章正文内容,下面案例可供参考

一、如何开启一个SpringBoot定时任务?

在我们日常开发中,开启并使用一个SpringBoot定时任务的大致步骤通常按如下所示

步骤

①在启动类上添加@EnableScheduling开启定时任务

示例代码如下

//开启定时任务
@EnableScheduling
@SpringBootApplication
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }

}

②编写定时任务,在其上添加@Scheduled设置任务执行时间

示例代码如下

 //每3秒执行一次
    @Scheduled(fixedRate = 3000)
    public void notifyA(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

③将定时任务所在的类上添加@Component

示例代码如下

@Component
public class springTimerTask {

    //每3秒执行一次
    @Scheduled(fixedRate = 3000)
    public void notifyA(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }
}

运行如下

在这里插入图片描述


二、cron表达式详解

在日常开发中,可以借助下面的网站快速生成cron表达式,提高开发效率

👉cron表达式在线生成器

2.1 语法格式

形式*******
字段SecondsMinutesHoursDayofMonthMonthDayofWeekYear
含义星期年(可选)
范围0-590-590-231-311-12(JAN-DEC)1-7 (SUN-SAT)
符号, - * /, - * /, - * /, - * /, - * / ? L C #, - * /, - * / ? L C #

备注

DayofWeek字段有效范围为1-7的整数或SUN-SAT两个范围。1表示星期天,2表示星期一,余下依次类推
Year字段有效范围为1970-2099年

2.2 符号解析

2,2.1 通用符号: , - * /

  • ,表示列出枚举值。例如:在Minutes域使用5,20,表示在时间的分钟数为5、20时触发事件
  • -表示范围。例如在Minutes域使用5-20,表示在时间的分钟数为5到20时每分钟都触发事件
  • *表示匹配该域的任意值。假如在Minutes:域使用,表示时间分钟数不做限制,每分钟都触发事件
  • /表示起始时间开始触发,然后每隔固定时间触发一次。例如在Minutes域使用5/20,表示时间的分钟数为5时触发一次,后隔20分钟即25、45再分别触发一次事件

举例说明

  • 0/2 * * * * ? : 表示每2秒 执行任务
  • 0 0/2 * * * ?表示每2分钟 执行任务
  • 0 0 2 1 * ?表示在每月的1日的凌晨2点调整任务

2.2.2 专有符号:?L w

  • ?只能用在DayofMonth和DayofWeek两个域,由于DayofMonthi和DayofWeek互斥,须对其一设置?
  • L表示最后,只能出现在DayofWeek和DayofMonth域。如果在DayofWeek域使用L,意味着在最后的一个星期四触发
  • W表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件
  • WL这两个字符可以连用,表示在某个月最后一个工作日
  • #用于确定每个月第几个星期几,只能出现在DayofWeek域。例如在4#2,表示某月的第二个星期三
  • C只能用在DayofMonth和DayofWeeki两个域,需要关联日历,如果没关联可以忽略

举例说明

  • 0 0-5 14 * * ? : 在每天下午2点到下午2:05期间的每1分钟触发
  • 0 10,44 14 ? 3 WED : 每年三月的星期三的下午2:10和2:44触发
  • 0 15 10 ? * MON-FRI : 周一至周五的上午10:15触发
  • 0 15 10 15 * ? : 每月15日上午10:15触发
  • 0 15 10 L * ? : 每月最后一日的上午10:15触发
  • 0 15 10 ? * 6L : 每月的最后一个星期五上午10:15触发
  • 0 15 10 ? * 6L 2002-2005: 2002年至2005年的每月的最后一个星期五上午10:15触发

注意

springBoot只支持cron表达式中的专有符号?,也仅仅支持6位的cron表达式,7位的不支持!!!

2.3 测试运行

示例代码如下

 //每2秒执行一次
    @Scheduled(cron = "0/2 * * * * ?")
    public void notifyA(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

运行如下

在这里插入图片描述


三、fixedRate & fixedDelay

如下可知,@Schedule里还可以使用以下两种类型的表达式,分别是“fixedDelay = xxx” 与 “fixedRate = xxx”
在这里插入图片描述

3.1 fixedRate

fixedRate属性是@Schedule注解中的一个属性,它表示以固定的频率执行某个方法或任务。此属性用于指定任务执行的时间间隔,单位为毫秒。

例如,如果设置为2000(即2秒),则任务将每隔2秒执行一次。

示例代码如下

//每2秒执行一次
    @Scheduled(fixedRate = 2000)
    public void notifyB(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

运行如下

在这里插入图片描述

注意

fixedRate是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。

测试代码如下

	//模拟任务阻塞4s,每2秒执行一次
    @Scheduled(fixedRate = 2000)
    public void notifyB() throws InterruptedException {
        Thread.sleep(4000);
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

运行如下

在这里插入图片描述

3.2 fixedDelay

fixedDelay属性是@Schedule注解中的一个属性,它表示以固定的时间间隔执行某个方法或任务,并在每次执行完成后等待指定的延迟时间再执行下一次。

fixedDelay属性用于指定任务执行之间的延迟时间,单位为毫秒。

例如,如果设置为2000(即2秒),则任务将每隔2秒执行一次,并且在每次执行完成后等待2秒再执行下一次。

示例代码如下

   //每2秒执行一次,并延迟2s
    @Scheduled(fixedDelay = 2000)
    public void notifyB(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

运行如下

在这里插入图片描述

注意

fixedDelay的执行时间是以上一次方法执行完开始算起,比如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次

举个具体的例子,如果在一个方法上设置了fixedDelay=5*1000(即5秒),那么当该方法某一次执行结束后,开始计算时间,当时间达到5秒,就开始再次执行该方法。这意味着无论任务实际执行需要多长时间,每个任务之间的延迟时间始终保持不变。

测试代码如下

	//模拟上次任务阻塞4s,然后间隔2秒执行下一次
    @Scheduled(fixedDelay = 2000)
    public void notifyB() throws InterruptedException {
        Thread.sleep(4000);
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }

运行如下

在这里插入图片描述


四、如何异步多线程的执行SprigBoot定时任务?

最简单的做法如下所示

步骤

①在启动类上添加注解@EnableAsync开启异步执行

示例代码如下

@EnableScheduling
@SpringBootApplication
@EnableAsync
public class MySpringBootApplication {

    public static void main(String[] args) {
        SpringApplication.run(MySpringBootApplication.class, args);
    }

}

②在定时任务上添加@Asynci设置异步执行

示例代码如下

@Component
public class springTimerTask {

    //每2秒执行一次
    @Async
    @Scheduled(cron = "0/2 * * * * ?")
    public void notifyA(){
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }


    //每3秒执行一次
    @Async
    @Scheduled(cron = "0/3 * * * * ?")
    public void notifyB() throws InterruptedException {
        String now = new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new Date());
        String name = Thread.currentThread().getName();
        System.out.println(name+"通知已发送"+",发送时间为"+now);
    }
}

运行如下

在这里插入图片描述

why?

Spring默认单线程的定时任务,如果不开启异步,多个任务都是同一个线程在处理,如果这个线程内的任务比较耗时,会导致后续任务延期; 开启异步后,每个任务都会从线程池里分配一个线程去完成,避免耗时长的任务,导致其他任务延期,故而上述代码在中存在多个线程在执行同一个任务的情况;

不信?请看如下不开启异步,多个定时任务同时运行的情形

在这里插入图片描述


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

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

相关文章

【JAVA】分布式链路追踪技术概论

目录 1.概述 2.基于日志的实现 2.1.实现思想 2.2.sleuth 2.2.可视化 3.基于agent的实现 4.联系作者 1.概述 当采用分布式架构后,一次请求会在多个服务之间流转,组成单次调用链的服务往往都分散在不同的服务器上。这就会带来一个问题:…

异常处理和单元测试python

一、实验题目 异常处理和单元测试 二、实验目的 了解异常的基本概念和常用异常类。掌握异常处理的格式、处理方法。掌握断言语句的作用和使用方法。了解单元测试的基本概念和作用。掌握在Python中使用测试模块进行单元测试的方法和步骤。 三、实验内容 编程实现如下功能&a…

跨平台Markdown编辑软件Typora mac功能介绍

Typora mac是一款跨平台的Markdown编辑器,支持Windows、MacOS和Linux操作系统。它具有实时预览功能,能够自动将Markdown文本转换为漂亮的排版效果,让用户专注于写作内容而不必关心格式调整。Typora Mac版除了支持常见的Markdown语法外&#x…

网站被CC攻击了怎么办?CC攻击有什么危害

网络爆炸性地发展,网络环境也日益复杂和开放,同时各种各样的恶意威胁和攻击日益增多,其中网站被CC也是常见的情况。 CC攻击有什么危害呢? 被CC会导致: 1.访问速度变慢:网站遭受CC攻击后,由于…

模式识别与机器学习(十一):Bagging

1.原理 Bagging [Breiman, 1996a] 是井行式集成学习方法最著名的代表.从名字即可看出,它直接基于自助采样法(bootstrap sampling)。给定包含m 个样本的数据集,我们先随机取出一个样本放入采样集中,再把该样本放回初始数据集,使得…

高频知识汇总 | 【操作系统】面试题汇总(万字长博通俗易懂)

前言 这篇我亲手整理的【操作系统】资料,融入了我个人的理解。当初我在研习八股文时,深感复习时的困扰,网上资料虽多,却过于繁杂,有的甚至冗余。例如,文件管理这部分,在实际面试中很少涉及&…

《PySpark大数据分析实战》-18.什么是数据分析

📋 博主简介 💖 作者简介:大家好,我是wux_labs。😜 热衷于各种主流技术,热爱数据科学、机器学习、云计算、人工智能。 通过了TiDB数据库专员(PCTA)、TiDB数据库专家(PCTP…

展望2023年CSDN博客之星评选

目录 1 前言2 博客的意义3 人工智能对博客的影响4 AI 技术下的成长与分享5 技术的探索6 博客之星评选对于技术人的激励作用7 结语 1 前言 当我们回顾过去,博客不仅仅是一种记录生活、分享经验的方式,更是一个见证自我成长与进步的平台。站在2023年度 CS…

Python算法例25 落单的数Ⅲ

1. 问题描述 给出2n2个非负整数元素的数组,除其中两个数字之外,其他每个数字均出现两次,找到这两个数字。 2. 问题示例 给出[1,2,2,3,4,4,5,3]&#xff0c…

SpringIOC之AbstractMessageSource

博主介绍:✌全网粉丝5W,全栈开发工程师,从事多年软件开发,在大厂呆过。持有软件中级、六级等证书。可提供微服务项目搭建与毕业项目实战,博主也曾写过优秀论文,查重率极低,在这方面有丰富的经验…

nodejs+vue+微信小程序+python+PHP计算机网络在线考试系统-计算机毕业设计推荐

信息数据的处理完全依赖人工进行操作, 所以电子化信息管理的出现就能缓解以及改变传统人工方式面临的处境,一方面可以确保信息数据在短时间被高效处理,还能节省人力成本,另一方面可以确保信息数据的安全性,可靠性&…

el-tree lazy懒加载(进阶版)

2023.12.22今天我学习了el-tree如何实现懒加载&#xff0c;效果如&#xff1a; 代码如下&#xff1a; 懒加载的使用不需要用:data <template><div><el-tree:props"props":load"loadNode"lazynode-key"id"show-checkbox/><…

新版IDEA中Git的使用(一)

说明&#xff1a;本文介绍如何在新版IDEA中使用Git 创建项目 首先&#xff0c;在GitLab里面创建一个项目&#xff08;git_demo&#xff09;&#xff0c;克隆到桌面上。 然后在IDEA中创建一个项目&#xff0c;项目路径放在这个Git文件夹里面。 Git界面 当前分支&Commit …

Pinely Round 3 (Div. 1 + Div. 2)(A~D)(有意思的题)

A - Distinct Buttons 题意&#xff1a; 思路&#xff1a;模拟从&#xff08;0,0&#xff09;到每个位置需要哪些操作&#xff0c;如果总共需要4种操作就输出NO。 // Problem: A. Distinct Buttons // Contest: Codeforces - Pinely Round 3 (Div. 1 Div. 2) // URL: https…

Leetcode—1962.移除石子使总数最小【中等】(最大堆做法)

2023每日刷题&#xff08;六十八&#xff09; Leetcode—1962.移除石子使总数最小 实现代码 class Solution { public:void downAdjustHeap(vector<int>& arr, int low, int high) {int i low, j i * 2 1;while(j < high) {if(j 1 < high && arr…

7.3电话号码的字母组合(LC17-M)

算法&#xff1a; 数字到字母要映射&#xff0c;可以用map&#xff0c;也可以用二维数组&#xff0c;或者直接用一个字符串 这里用字符串&#xff0c;键入的数字对应字符串的索引 String[] numString {"", "", "abc", "def", &quo…

前端开发有了 Next.js,还需要后端开发吗 ?

前言 在迅速变化的Web开发领域&#xff0c;选择正确的工具和框架对于打造优秀的用户体验至关重要。Next.js&#xff0c;作为React框架的佼佼者&#xff0c;因其前后端流畅集成而受到广泛欢迎。这就引出了一个有趣的问题&#xff1a;我们真的需要Next.js的后端功能吗&#xff1f…

ESP32+LVGL笔记(6)-把712k的一二级汉字字库放在SPIRAM

文章目录 1.字库制作2.字库烧录到ESP32-S3的flash2.1 配置好分区文件2.2 汉字库文件烧录到ESP32的flash 3.将字库从 flash 拷贝到 SPIRAM3.1 工程配置中有关 SPIRAM 部分3.2 将汉字库从flash拷贝到SPIRAM的代码3.3 在进入lvgl之前调用函数 copyHZK_from_flash_to_SPIRAM 在前面…

部署LNMP动态网站

部署LNMP动态网站 安装LNMP平台相关软件1. 安装软件包2. 启动服务&#xff08;nginx、mariadb、php-fpm&#xff09;3. 修改Nginx配置文件&#xff0c;实现动静分离4. 配置数据库 上线wordpress代码 &#xff08;测试搭建的LNMP环境是否可以使用&#xff09;1. 上线php动态网站…

【机器学习】模式识别

1 概述 模式识别&#xff0c;简单来讲&#xff0c;就是分类问题。 模式识别应用&#xff1a;医学影像分析、人脸识别、车牌识别、遥感图像 2 模式分类器 分类器的分类&#xff1a;线性分类器、非线性分类器、最近邻分类器 2.1 分类器的训练&#xff08;学习&#xff09;过…