当前位置: 首页 > article >正文

Idea实现定时任务

定时任务

什么是定时任务?

可以自动在项目中根据设定的时长定期执行对应的操作

实现方式

Spring 3.0 版本之后自带定时任务,提供了@EnableScheduling注解和@Scheduled注解来实现定时任务功能。

使用SpringBoot创建定时任务非常简单,目前主要有以下三种创建方式:

1、基于注解(@Scheduled)

2、基于注解设定多线程定时任务

1、基于注解(@Scheduled)

1.1 @Scheduled和@EnableScheduling

基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。

@EnableScheduling注解: 在配置类上使用,开启计划任务的支持(类上)。

@Scheduled注解: 来声明这是一个任务,包括 cron,fixDelay,fixRate 等类型(方法上,需先开启计划任务的支持)。

1.1.1开启定时任务

SpringBoot 项目在项目启动类上添加 @EnableScheduling 注解即可开启定时任务管理。

1.1.2添加定时任务

1.1.2.1 fixedRate

finexRate:间隔的时间(单位为毫秒)

这时候就可以在下方定义测试方法,添加@Scheduling注解,开启一个定时方法

此时上面的方法每五秒执行一次,下面的方法每10秒执行一次,这个时候我们运行看一下控制台会输出什么

此时可以看到,在启动后立马执行了第一次,而第一次执行的顺序也是随机的,后面的每次执行都是根据定义的时长来进行轮流执行

如果遇到两个方法同一时间执行,则会根据谁的间隔时间短来判断,故上方是(朵拉)先执行

1.1.2.2 cron

该参数接收一个cron表达式,cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个域,每一个域代表一个含义。

cron 表达式语法:

格式:[秒] [分] [小时] [日] [月] [周] [年]

序号说明是否必填允许填写的值允许的通配符
10-59, - * /
20-59, - * /
3小时0-23, - * /
41-31, - * ? / L W
51-12 or JAN-DEC, - * /
61-7 or SUN-SAT, - * ? / L #
7empty 或 1970-2099, - * /

通配符说明:

*表示所有值. 例如:在分的字段上设置 "*",表示每一分钟都会触发。

? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为"?" 具体设置为 0 0 0 10 * ?

-表示区间。例如 在小时上设置 "10-12",表示 10,11,12点都会触发。

, 表示指定多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发

/ 用于递增触发。如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)。在月字段上设置'1/3'所示每月1号开始,每隔三天触发一次。

L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于"7"或"SAT"。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示“本月最后一个星期五"

W 表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-").

# 序号(表示每月的第几个周几),例如在周字段上设置"6#3"表示在每月的第三个周六.注意如果指定"#5",正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了)

现在,我们逐个解析

(1)*

任何地方都可使用,表示所有

现在就实现了每秒提醒朵拉吃饭,这样可以保证朵拉的饮食,防止变瘦

(2)?

仅可以在日期星期几中使用,表示不在乎时间

此图是实现在每月的第一天上午10点运行,但由于一个月只能实现一次,目前无控制台输出

例如:八月份的1号是周一,但九月份的1号不是周一,但是使用了就可以实现每月一号都输出

(3)/

任何地方都可使用,表示多久一次

朵拉每时每刻都能提醒吃饭,此时李勇杰不乐意了,为什么朵拉可以有人提醒,而自己没有,所以现在来提醒李勇杰吃东西

如果是上方朵拉的提醒方式,那么李勇杰就会撑死,所以我们要对他进行区间提醒,防止李勇杰被撑死了

此时可以看到,这时候我们使用传统的方式,李勇杰就会被撑死

那么肯定不能设定这么短的提醒时间

这个时候就可以实现从0点开始,每隔6小时提醒一次(时间过长不展示)

(4)-

任何地方都可使用,表示区间

上方的/是隔多久执行一次,并不能准确到某个时间点,如果要实现在9点22点之间每个小时都能提醒

就可以 使用到区间

上方这张图表示从9点22点之间,并且每分钟的0秒30秒之间,每秒都提醒一次

此时控制台就会根据间隔时间输出

(5),

在任何地方都可以使用、表示多种选择

如果此时想自定义的提醒,而不是根据指定间隔来提醒,这样就可以使用来实现

此图表达的意思是:在9-22点时间内,每执行到0,10,15,30,32,38,40,48,55秒的时候,就会给出提醒,这样就可以实现无规则的提醒

这里就可以看到每次到了指定的时间,就会提醒一次,这样就实现了无规则提醒

下方是一些经典案例

0 0 12 * * ?每天12点触发
0 15 10 ? * *每天10点15分触发
0 15 10 * * ?每天10点15分触发
0 15 10 * * ? *每天10点15分触发
0 15 10 * * ? 20052005年每天10点15分触发
0 * 14 * * ?每天下午的 2点到2点59分每分触发
0 0/5 14 * * ?每天下午的 2点到2点59分(整点开始,每隔5分触发)
0 0-5 14 * * ?每天下午的 2点到2点05分每分触发
0 10,44 14 ? 3 WED3月分每周三下午的 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分触发
0 15 10 ? * 6#3每月的第三周的星期五开始触发
0 0 12 1/5 * ?每月的第一个中午开始每隔5天触发一次
0 11 11 11 11 ?每年的11月11号 11点11分触发(光棍节)

另外,cron属性接收的cron表达式支持占位符。eg:

配置文件:

time:
  cron: */5 * * * * *
  interval: 5
每5秒执行一次:

@Scheduled(cron="${time.cron}")
void testPlaceholder1() {
    System.out.println("Execute at " + System.currentTimeMillis());
}
 
@Scheduled(cron="*/${time.interval} * * * * *")
void testPlaceholder2() {
    System.out.println("Execute at " + System.currentTimeMillis());
}

结果如下:

1.1.2.3 zone

时区,接收一个 java.util.TimeZone#ID。cron表达式会基于该时区解析。默认是一个空字符串,即取服务器所在地的时区。比如我们一般使用的时区Asia/Shanghai。该字段我们一般留空。

1.1.2.4 fixedDelay

上一次执行完毕时间点之后多长时间再执行。如:

@Scheduled(fixedDelay = 5000) //上一次执行完毕时间点之后5秒再执行

1.1.2.5 fixedDelayString

与 1.2.4 fixedDelay 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。如:

@Scheduled(fixedDelayString = "5000") //上一次执行完毕时间点之后5秒再执行

占位符的使用:

在 application.yml 配置文件中添加如下配置:

time:
  fixedDelay: 5000
编写相关代码:

@EnableScheduling
@SpringBootApplication
public class DemoApplication
{
    @Scheduled(fixedDelayString = "${time.fixedDelay}")
   public void test2() {
        System.out.println("李勇杰,该吃*了" + DateFormat.getDateTimeInstance().format(new Date()));
    }
}

执行结果:

1.1.2.6 fixedRateString

与 1.2.1 fixedRate 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。

1.1.2.7 initialDelay

第一次延迟多长时间后再执行。如:

@Scheduled(initialDelay=1000, fixedRate=5000) //第一次延迟1秒后执行,之后按fixedRate的规则每5秒执行一次

1.1.2.8 initialDelayString

与 1.2.7 initialDelay 意思相同,只是使用字符串的形式。唯一不同的是支持占位符。

2、基于注解设定多线程定时任务

创建多线程定时任务。

package com.pjb.Task;
 
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
 
/**
 * 基于注解设定多线程定时任务
 * @author pan_junbiao
 */
@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)
    public void second() {
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
        System.out.println();
    }
}

注意:由于基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。所以这里使用 @Async 注解很关键。

从控制台可以看出,第一个定时任务和第二个定时任务互不影响;

并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。


http://www.kler.cn/a/429506.html

相关文章:

  • HarmonyOS 鸿蒙 ArkTs(5.0.1 13)实现Scroll下拉到顶刷新/上拉触底加载,Scroll滚动到顶部
  • 《AI创造力的边界与机器人技术的现实困境:一个双重视角的探讨》
  • 总结SpringBoot项目中读取resource目录下的文件多种方法
  • 《零基础Go语言算法实战》【题目 2-30】并发安全问题
  • Spring Boot 应用开发入门
  • PCB印刷电路板快速上手04电容元件
  • Spark架构及运行流程
  • 【源码解读】SpringMMVC执行流程
  • 教程|使用Conda安装AlphaFold3-个人记录以及遇到的问题
  • CLIP论文提炼与代码实战
  • node.js 环境配置
  • leetcode207:课程表
  • C#的基本类型,一篇很基础的文章
  • NLP-实体识别
  • Linux,如何要定位并删除占用磁盘空间的大文件?
  • 换一个ip地址是什么意思?换一个网络ip地址会变吗
  • AI如何让PPT制作变得轻松与智能?用一键生成ppt!
  • HTML DOM API
  • MFC中如何创建一个非模态对话框
  • TEA系列例题
  • 开源轻量级文件分享服务Go File本地Docker部署与远程访问
  • 使用docker-compose安装Milvus向量数据库及Attu可视化连接工具
  • 物理学:什么是核聚变?
  • .Net学习
  • el-dialog修改其样式不生效加deep也没用
  • 从零用java实现 小红书 springboot vue uniapp (1)