【SpingBoot定时任务】Spring自带@Scheduled、异步多线程@Async、quartz框架 定时任务示例
创始人
2024-03-15 09:18:53
0

文章目录

    • springboot定时任务
      • 1、基于注解(@Scheduled)
      • 2、异步多线程使用定时任务
      • 3、使用quartz实现定时任务
        • 使用Springboot整合Quartz定时任务框架

springboot定时任务

在springboot环境中,实现定时任务有两种方案:

  • 使用 Spring 自带的定时任务处理器 @Scheduled 注解。Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略
  • 使用第三方框架 Quartz

@EnableScheduling

1、基于注解(@Scheduled)

/*** 定时任务*/
@Configuration      // 1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
public class StaticScheduleTask {//3.添加定时任务  每隔5秒调用一次@Scheduled(cron = "0/5 * * * * ?")public void configureTasks() {System.err.println("执行静态定时任务时间: " + LocalDateTime.now());}
}

在这里插入图片描述

cron = [秒] [分] [小时] [日] [月] [周] [年]
注意:

  • 在周中1表示周日,2才表示周一,以此类推,7表示周六。
  • 在cron表达式中不区分大小写,即sun和SUN等价。
  • 月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是 ?
  • 此处给大家提供一个cron表达式生成器https://www.matools.com/cron/
序号说明是否必填允许填写的值允许的通配符
10-59, - * /
20-59, - * /
30-23, - * /
41-31, - * ? / L W C
51-12或JAN~DEC, - * /
61-7 或 SUN/MON/TUE/WED/THU/FRI/SAT, - * ? / L C #
7空或1970-2099, - * /

规则:

  • ?:表示不指定值,即不关心某个字段的取值时使用。需要注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是?
  • *:表示所有值,例如:在秒的字段上设置 *,表示每一秒都会触发
  • ,:用来分开多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发
  • -:表示区间,例如在秒上设置 “10-12”,表示 10,11,12秒都会触发
  • /:用于递增触发,如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)
  • #:序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六,(用 在母亲节和父亲节再合适不过了)周字段的设置,若使用英文字母是不区分大小写的 ,即 MON 与mon相同
  • L:表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会自动判断是否是润年),在周字段上表示星期六,相当于"7"或"SAT"(注意周日算是第一天)。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示"本月最后一个星期五"
  • W:表示离指定日期的最近工作日(周一至周五),例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发,如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,“W"前只能设置具体的数字,不允许区间”-“)
    L 和 W 可以一组合使用。如果在日字段上设置"LW”,则表示在本月的最后一个工作日触发


2、异步多线程使用定时任务

【同时执行多个定时任务,会出现高并发问题(同一数据来不及更新),所以就存在创建多线程定时任务。】
示例一:

@Configuration      // 1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling   // 2.开启定时任务
@EnableAsync        // 4.开启多线程
public class SaticScheduleTask {//3.添加定时任务@Scheduled(cron = "0/5 * * * * ?")@Async //异步方法  异步调用  默认为同步//@Transactional //添加事务public void configureTasks() {//每次执行会产生一个新的线程System.err.println(Thread.currentThread.getName()+"执行静态定时任务时间: " + LocalDateTime.now());}
}

在这里插入图片描述


示例二:

@Component
@EnableScheduling   // 1.开启定时任务
@EnableAsync        // 2.开启多线程
public class MultithreadScheduleTask {@Async@Scheduled(fixedDelay = 1000)  //间隔1秒public void first() throws InterruptedException {System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());System.out.println();Thread.sleep(1000 * 10);}@Async@Scheduled(fixedDelay = 2000)   //间隔2秒public void second() {System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());System.out.println();}}

第一个和第二个定时任务互不影响;并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。
在这里插入图片描述

根据Spring的文档说明,默认采用的是单线程的模式的。所以在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的。

那么当多个任务的执行势必会相互影响。例如,如果A任务执行时间比较长,那么B任务必须等到A任务执行完毕后才会启动执行。又如在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring3.x之后,已经内置了@Async来完美解决这个问题。

3、使用quartz实现定时任务

官网:http://www.quartz-scheduler.org/
使用一种新的框架,自然要引入jar包,版本就随springboot


org.springframework.bootspring-boot-starterquartz

使用Springboot整合Quartz定时任务框架

  • 任务Job:job就是你想要实现的任务类,每一个job必须实现org.quartz.job接口。
  • 触发器Trigger: Trigger为你执行任务的触发器,比如你想每天定时某点发送一份统计邮件,Trigger将会设置某点进行执行该任务。
  • 调度器Scheduler:Scheduler为任务的调度器,它会将任务job及触发器Trigger整合起来,负责基于Trigger设定的时间来执行Job

示例:每隔两秒发一次任务,发5次

jar包

org.quartz-schedulerquartz2.3.2slf4j-apiorg.slf4j

org.quartz-schedulerquartz-jobs2.3.2


org.slf4jslf4j-api1.7.7


org.springframeworkspring-context-support


org.springframeworkspring-tx

job任务类:

public class QuartzDemo implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {System.out.println("Execute..." + new Date());}
}

配置类:配置触发器与任务调度器

/*** quartz配置类*/
@Configuration
public class QuartzConfig {/*** 1、创建Job对象*/@Beanpublic JobDetailFactoryBean jobDetailFactoryBean(){JobDetailFactoryBean factoryBean=new JobDetailFactoryBean();//关联我们自己的Job类factoryBean.setJobClass(QuartzDemo.class);return factoryBean;}/*** 2、创建Trigger对象*/@Beanpublic SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){SimpleTriggerFactoryBean factoryBean=new SimpleTriggerFactoryBean();//关联JobDetail对象factoryBean.setJobDetail(jobDetailFactoryBean.getObject());//该参数表示一个执行的毫秒数factoryBean.setRepeatInterval(2000); //每隔2秒执行一次//重复次数factoryBean.setRepeatCount(5);return factoryBean;}/*** 3、创建Scheduler*/@Beanpublic SchedulerFactoryBean schedulerFactoryBean(SimpleTriggerFactoryBean simpleTriggerFactoryBean){SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();//关联triggerfactoryBean.setTriggers(simpleTriggerFactoryBean.getObject());return factoryBean;}
}

项目的启动类启动运行:

@SpringBootApplication
@EnableScheduling
public class SpringBootCrontabApplication extends SpringBootServletInitializer {public static void main(String[] args) {SpringApplication.run(SpringBootCrontabApplication.class, args);}
}

在这里插入图片描述

相关内容

热门资讯

专访鲁政委:结构性货币政策工具... 2025年,站在“十四五”收官与“十五五”规划谋篇的历史衔接点上,中国经济在多重变局中展现出韧性,金...
广末凉子有望明年复出!曾飙速1... 搜狐娱乐讯 据日媒,广末凉子有望明年正式复出,相关人士称她一直很规矩,会向各界发邮件汇报近况,“这次...
浙江东日(600113)发布投... 截至2025年12月25日收盘,浙江东日(600113)报收于67.29元,较前一交易日上涨4.34...
广电网络:近12个月累计诉讼及... 中证智能财讯 广电网络(600831)12月25日晚间发布累计诉讼、仲裁情况公告,近十二个月内,公司...
封关后第一批!198公斤椰子油... 12月23日,海南保亭黎族苗族自治县一家食品企业生产的198公斤初榨椰子油,通过海口新海港和南港“二...
过山车上呕吐物从天而降弄脏羽绒... 男子张某和女朋友到游乐园游玩,途经过山车下方时,被上方不明人员的呕吐物滴落在其羽绒服及围巾上,事后张...
定南县林业局专题学习《森林草原... 12月25日,江西省赣州市定南县林业局组织干部职工开展《森林草原防灭火条例》专题学习,全面贯彻落实新...
当律师遇上AI:Equall如... 这项由Equall公司的Pierre Colombo、Malik Boudiaf等研究团队共同完成的...
字节跳动通报:120人被辞退,... 12月25日记者获悉,字节跳动企业纪律与职业道德委员会发布通报,披露2025年三季度内部违规案例的处...