聊一聊非分布式任务调度@Scheduled

news/2024/11/24 17:14:26/

@Scheduled注解是Spring Boot提供的用于定时任务控制的注解,主要用于控制任务在某个指定时间执行,或者每隔一段时间执行,默认是在单线程中执行的

1、注解源码

@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(Schedules.class)
@Reflective
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 "";TimeUnit timeUnit() default TimeUnit.MILLISECONDS;
}

2、参数说明

参数说明示例
cron任务执行的cron表达式0/1 * * * * ?
zonecron表达时解析使用的时区,默认为服务器的本地时区,使用java.util.TimeZone#getTimeZone(String)方法解析GMT-8:00
fixedDelay上一次任务执行结束到下一次执行开始的间隔时间,单位为ms2000
fixedDelayString上一次任务执行结束到下一次执行开始的间隔时间,使用java.time.Duration#parse解析PT15M
fixedRate以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务2000
fixedRateString与fixedRate逻辑一致,只是使用java.time.Duration#parse解析PT15M
initialDelay首次任务执行的延迟时间2000
initialDelayString首次任务执行的延迟时间,使用java.time.Duration#parse解析PT15M
timeUnit

3、详解说明

1、cron 参数

表达式格式:@Scheduled(cron = "{秒数} {分钟} {小时} {日期} {月份} {星期}")

注意: cron表达式可分为6或7个占位符,但在spring自带的定时任务中,cron只支持6个参数,若使用7个参数就会报错

Caused by: java.lang.IllegalStateException: Encountered invalid @Scheduled method 'test': Cron expression must consist of 6 fields (found 7 in "*/5 * * * * * *")

代码示例:

/*** cron 表达式 每隔5秒执行一次*/
@Scheduled(cron = "*/5 * * * * *")
public void test(){log.info("小熊学Java是最全Java学习网站!");
}

结果

2023-06-28T15:20:40.009+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:45.014+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:50.004+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:20:55.010+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!
2023-06-28T15:21:00.002+08:00  INFO 10904 --- [   scheduling-1] com.javaxiaobear.job.MyScheduledJob      : 小熊学Java是最全Java学习网站!

更多的cron表达式,自行测试哈,这里不做过多演示

“30 * * * * ?” 每半分钟触发任务 “30 10 * * * ?” 每小时的10分30秒触发任务 “30 10 1 * * ?” 每天1点10分30秒触发任务 “30 10 1 20 * ?” 每月20号1点10分30秒触发任务 “30 10 1 20 10 ? *” 每年10月20号1点10分30秒触发任务 “30 10 1 20 10 ? 2011” 2011年10月20号1点10分30秒触发任务 “30 10 1 ? 10 * 2011” 2011年10月每天1点10分30秒触发任务 “30 10 1 ? 10 SUN 2011” 2011年10月每周日1点10分30秒触发任务 “15,30,45 * * * * ?” 每15秒,30秒,45秒时触发任务 “15-45 * * * * ?” 15到45秒内,每秒都触发任务 “15/5 * * * * ?” 每分钟的每15秒开始触发,每隔5秒触发一次 “15-30/5 * * * * ?” 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次 “0 0/3 * * * ?” 每小时的第0分0秒开始,每三分钟触发一次 “0 15 10 ? * MON-FRI” 星期一到星期五的10点15分0秒触发任务 “0 15 10 L * ?” 每个月最后一天的10点15分0秒触发任务 “0 15 10 LW * ?” 每个月最后一个工作日的10点15分0秒触发任务 “0 15 10 ? * 5L” 每个月最后一个星期四的10点15分0秒触发任务 “0 15 10 ? * 5#3” 每个月第三周的星期四的10点15分0秒触发任务

2、fixedDelay 参数

fixedDelay 上一次任务执行结束到下一次执行开始的间隔时间,单位为ms

代码示例:

/*** fixedDelay 上一次任务执行结束到下一次执行开始的间隔时间,单位为ms* 每隔2秒执行一次*/
@Scheduled(fixedDelay = 2000)
public void testFixedDelay (){log.info("小熊学Java是最全Java学习网站!");
}

结果展示:

image-20230628153022010

3、fixedRate参数

以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务

/*** 以固定间隔执行任务,即上一次任务执行开始到下一次执行开始的间隔时间,单位为ms,若* 在调度任务执行时,上一次任务还未执行完毕,会加入worker队列,等待上一次执行完成后立即执行下一次任务* 每隔2秒执行一次*/@Scheduled(fixedRate = 2000)public void testFixedRate () throws InterruptedException {Thread.sleep(3000);log.info("小熊学Java是最全Java学习网站!");}

日志每3秒执行一次,这也是因为@Scheduled是在单线程中执行的

image-20230629161133953

4、initialDelay参数

首次任务执行的延迟时间

/*** initialDelay  首次任务执行的延迟时间* 每隔2秒执行一次*/@Scheduled(fixedRate = 2000, initialDelay = 3000)public void testInitialDelay (){log.info("小熊学Java是最全Java学习网站!");}

首次延迟的时间是3秒,之后每2秒执行一次

image-20230629161513224

4、@Scheduled多线程

1、场景演示

执行以下两个方法

@Scheduled(fixedRate = 2000)
public void test1 () throws InterruptedException {Thread.sleep(3000);log.info("小熊学Java 是最全Java学习网站!---test1");
}
@Scheduled(fixedRate = 2000)
public void test2 () throws InterruptedException {Thread.sleep(3000);log.info("小熊学Java是最全Java学习网站!---test2");
}

image-20230629162300742

从执行结果中可以看出,test1方法和test2方法交替输出日志,并没有同时执行

org.springframework.scheduling.config.ScheduledTaskRegistrar源码发现

protected void scheduleTasks() {//如果为空,则以单线程执行if (this.taskScheduler == null) {this.localExecutor = Executors.newSingleThreadScheduledExecutor();this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}Iterator var1;if (this.triggerTasks != null) {var1 = this.triggerTasks.iterator();while(var1.hasNext()) {TriggerTask task = (TriggerTask)var1.next();this.addScheduledTask(this.scheduleTriggerTask(task));}}if (this.cronTasks != null) {var1 = this.cronTasks.iterator();while(var1.hasNext()) {CronTask task = (CronTask)var1.next();this.addScheduledTask(this.scheduleCronTask(task));}}IntervalTask task;if (this.fixedRateTasks != null) {var1 = this.fixedRateTasks.iterator();while(var1.hasNext()) {task = (IntervalTask)var1.next();if (task instanceof FixedRateTask) {FixedRateTask fixedRateTask = (FixedRateTask)task;this.addScheduledTask(this.scheduleFixedRateTask(fixedRateTask));} else {this.addScheduledTask(this.scheduleFixedRateTask(new FixedRateTask(task)));}}}if (this.fixedDelayTasks != null) {var1 = this.fixedDelayTasks.iterator();while(var1.hasNext()) {task = (IntervalTask)var1.next();if (task instanceof FixedDelayTask) {FixedDelayTask fixedDelayTask = (FixedDelayTask)task;this.addScheduledTask(this.scheduleFixedDelayTask(fixedDelayTask));} else {this.addScheduledTask(this.scheduleFixedDelayTask(new FixedDelayTask(task)));}}}}

当未手动指定taskScheduler时,会通过Executors.newSingleThreadScheduledExecutor()创建默认的单线程线程池,且该线程池的拒绝策略为AbortPolicy,这种策略在线程池无可用线程时丢弃任务,并抛出异常RejectedExecutionException

2、多线程配置

1、配置bean

在启动类中,配置bean,代码如下:

/*** 配置线程池* @return*/
@Bean
public TaskScheduler config(){ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();//线程池大小为10taskScheduler.setPoolSize(10);return taskScheduler;
}

image-20230629162818136

2、配置类

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {//Scheduler指定线程池taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));}
}

运行结果跟上面一样,每3秒同时执行

5、Async异步执行

异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。

1、简单使用

Spring Boot的异步任务,只需在方法上添加异步注解,同时开启异步任务

@Component
@Slf4j
public class AsyncTask {@Asyncpublic void test(){log.info("小熊学Java 是最棒的!!!");}
}

方法调用

@Resourceprivate AsyncTask asyncTask;@Scheduled(fixedRate = 2000)public void test1 () throws InterruptedException {asyncTask.test();Thread.sleep(3000);log.info("小熊学Java 是最全Java学习网站!---test1");}

结果输出

image-20230629170457246

2、异步失效

1、异步方法和调用异步方法在同一个类中

有时候,经常看到编写异步任务,都是这样写的

@Scheduled(fixedRate = 2000)
public void test1 () throws InterruptedException {asyncTask.test();Thread.sleep(3000);log.info("小熊学Java 是最全Java学习网站!---test1");
}@Async
public void test(){log.info("小熊学Java 是最棒的!!!");
}

这样写是不会生效的,由于@Async的AdviceMode默认为PROXY,所以当调用方和被调用方是在同一个类中,无法产生切面,@Async没有被Spring容器管理,可以查看源码,具体详情可参考这篇:https://juejin.cn/post/6976893903223914527#heading-5

好了,本文就到这里了!如果觉得内容不错的话,希望大家可以帮忙点赞转发一波,这是对我最大的鼓励,感谢🙏🏻

资料获取👇 最后面就是领取暗号,公众号回复即可!


http://www.ppmy.cn/news/653716.html

相关文章

(2023最新)互联网1010道Java面试真题汇总

我相信各位小伙伴们都发现了,现在的 IT 的环境并不如以前了,似乎是迎来“寒冬”,再加上最近上热搜的阿里云大裁员事件,又将 Java 开发岗推上了一个新的难度。而被裁员的人,不得不降薪重新找到一份工作,而经…

给小孩用电动牙刷好不好

 有一个有趣的统计数字:购买电动牙刷的消费者通常以两种类型居多:一是时尚情侣,买电动牙刷同样也是为了追求时尚与健康;二是有孩子的家庭,孩子不喜欢刷牙、或者孩子刷牙的姿势不正确&#xff…

一步一步学OAK之七:通过OAK相机实现特征跟踪

目录 特征跟踪Setup 1: 创建文件Setup 2: 安装依赖Setup 3: 导入需要的包Setup 4: 定义FeatureTrackerDrawer类定义变量定义onTrackBar方法定义trackFeaturePath方法定义drawFeatures方法定义FeatureTrackerDrawer类的构造函数 Setup 5: 创建pipelineSetup 6: 创建节点创建相机…

多种拖拽= =自用留档

<template> <div class"main-drag"> <div v-if"stencil 0" class"mapped-fields"> <el-form ref"mapped" :model"mapped" class"demo-fieldsForm"> <el-form-item label"切换数…

‘PHPExcel_Calculation_Exception‘ with message ‘Worksheet!G32 -> Formula Error: Unexpected ,‘ in

原因&#xff1a;PHPExcel 数据问题&#xff0c;存在英文字符 ,解决&#xff1a; 用 setCellValueExplicit() 把所有的输出到 Excel 表格的数据强制转为字符串 $sheet->setCellValueExplicit(A . $i, $val[fud_remark], PHPExcel_Cell_DataType::TYPE_STRING2);

用vulkan写个引擎 (四)PBR着色器

PBR全称(Physicallly-Based Rendering)&#xff0c;基于物理的渲染。本文将提供一份GLSL实用型着色器。对于理论部分网络上已经有太多文章了。 仓库&#xff1a;https://bitbucket.org/mm_longcheng/mm-vulkan 扣扣交流群&#xff1a;554329899 一、着色器入参问题 对于着色…

Vulkan开发实战详解 学习笔记 - 构建一个球体对象

构建一个球体对象 BallData.h #ifndef VULKANEXBASE_BALLDATA_H #define VULKANEXBASE_BALLDATA_H//防止重复引用 class BallData { public:static float* vdata;//顶点数据数组首地址指针static int dataByteCount;//顶点数据所占总字节数static int vCount;//顶点数量stat…

安装oracle10g32,Windows7旗舰版32位安装oracle10g方法

Windows7旗舰版32位安装oracle10g方法 首先要下载支持Vista版本的Oracle 10g 下载完成后解压出来&#xff1a; http://www.doczj.com/doc/816ed069b84ae45c3b358c7a.html/otn/nt/oracle10g/10203/10203_vista_w2k8_x86_production_d b.zip安装的第一步就是要修改安装文件目录中…