赞
踩
/** * 定时任务 * 1、@EnableScheduling 开启定时任务 * 2、@Scheduled 开启一个定时任务 * 3、自动配置类 TaskSchedulingAutoConfiguration * 异步任务 * 1、@EnableAsync 开启异步任务功能 * 2、@Async 方法异步执行 * 3、自动配置类 TaskExecutionAutoConfiguration */ /** * 在Spring中 只允许6位 [* * * ? * 1] : 每周一每秒执行一次 * [* /5 * * ? * 1] : 每周一 每5秒执行一次 * * 定时任务默认是阻塞的,不应该阻塞。 * 解决阻塞方案: * 1、可以让业务用异步方式运行,自己提交到线程池 * 2、让定时任务异步执行 @EnableAsync + @Async * */
@Scheduled
定时任务的核心。
@Scheduled
默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。
参数解析:
cron
: cron表达式,根据表达式循环执行,与fixedRate
属性不同的是它是将时间进行了切割。(@Scheduled(cron = "0/5 * * * * *"
)任务将在5、10、15、20...
这种情况下进行工作)fixedRate
: 每隔多久执行一次;(@Scheduled(fixedRate = 1000
) 假设第一次工作时间为2018-05-29 16:58:30
,工作时长为3秒,那么下次任务的时候就是2018-05-29 16:58:33
,配置成异步后,只要到了执行时间就会开辟新的线程工作),如果(@Scheduled(fixedRate = 3000
) 假设第一次工作时间为2018-05-29 16:58:30
,工作时长为1秒,那么下次任务的时间依然是2018-05-29 16:58:33
)fixedDelay
: 当前任务执行完毕后等待多久继续下次任务(@Scheduled(fixedDelay = 3000
) 假设第一次任务工作时间为2018-05-29 16:54:33
,工作时长为5秒,那么下次任务的时间就是2018-05-29 16:54:41
)initialDelay
: 第一次执行延迟时间,只是做延迟的设定,与fixedDelay
关系密切,配合使用,相辅相成。@Async
代表该任务可以进行异步工作,由原本的串行改为并行。
单线程案例:
@Slf4j @Component @EnableScheduling // 开启定时任务 public class SpringTask { @Scheduled(cron = "0/1 * * * * *") public void scheduled2() throws InterruptedException { Thread.sleep(3000); log.info("scheduled2 每1秒执行一次:{}", LocalDateTime.now()); } @Scheduled(fixedRate = 1000) public void scheduled1() throws InterruptedException { Thread.sleep(3000); log.info("scheduled1 每1秒执行一次:{}", LocalDateTime.now()); } }
发现两个任务都是同一个线程,任务之间会相互影响。
多线程案例:
@Slf4j @Component @EnableScheduling // 开启定时任务 @EnableAsync // 开启多线程 public class SpringTask { @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(); } }
从控制台可以看出,第一个定时任务和第二个定时任务互不影响;
并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。
Cron表达式参数分别表示:
cron表达式在线生成: http://cron.qqe2.com/
显然,使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。
数据库脚本。
CREATE TABLE `cron` (
`cron_id` varchar(30) NOT NULL PRIMARY KEY,
`cron` varchar(30) NOT NULL
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
创建定时器。
这里添加的是TriggerTask,目的是循环读取数据库设置好的执行周期,以及执行相关定时任务的内容。
具体代码如下:
@Component @EnableScheduling // 开启定时任务 public class DynamicScheduleTask implements SchedulingConfigurer { @Resource CronService cronService; @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { // 定时任务要执行的内容 Runnable task = ()->{ System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()); }; // 设置执行周期 Trigger trigger = triggerContext -> { List<Cron> crons = cronService.list(); String cron = crons.get(0).getCron(); // 合法性校验. if (StringUtils.isEmpty(cron)) { // Omitted Code .. } // 返回执行周期(Date) return new CronTrigger(cron).nextExecutionTime(triggerContext); }; // 注册一个任务 taskRegistrar.addTriggerTask(task, trigger); } }
测试。
打印时间是每5秒一次,
将执行周期修改为每3秒执行一次,
发现执行周期已经改变,并且不需要重启应用。
注意: 如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
一般出现在SpringMVC的项目中,因为有两个上下文,一个是SpringMVC容器,一个Spring容器,
如果你的定时任务类同时被两个容器管理了,就会执行两次。
解决方案是只被一个容器来管理。
cron表达式实际上是由七个子表达式组成。这些表达式之间用空格分隔:
1、Seconds (秒)
2、Minutes(分)
3、Hours(小时)
4、Day-of-Month (天)
5、Month(月)
6、Day-of-Week (周)
7、Year(年)
例: 0 0 12 ? * WED
意思是:每个星期三的中午12点执行。
子表达式范围:
1、Seconds (0~59)
2、Minutes (0~59)
3、Hours (0~23)
4、Day-of-Month (1~31,但是要注意有些月份没有31天)
5、Month (0~11,或者"JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV,DEC")
6、Day-of-Week (1~7,1=SUN 或者"SUN, MON, TUE, WED, THU, FRI, SAT”)
7、Year (1970~2099)
表达式例子:
0 * * * * ?
每1分钟触发一次
0 0 * * * ?
每天每1小时触发一次
0 0 10 * * ?
每天10点触发一次
0 * 14 * * ?
在每天下午2点到下午2:59期间的每1分钟触发
0 30 9 1 * ?
每月1号上午9点半
0 15 10 15 * ?
每月15日上午10:15触发
*/5 * * * * ?
每隔5秒执行一次
0 */1 * * * ?
每隔1分钟执行一次
0 0 5-15 * * ?
每天5-15点整点触发
0 0/3 * * * ?
每三分钟触发一次
0 0-5 14 * * ?
在每天下午2点到下午2:05期间的每1分钟触发
0 0/5 14 * * ?
在每天下午2点到下午2:55期间的每5分钟触发
0 0/5 14,18 * * ?
在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
0 0/30 9-17 * * ?
朝九晚五工作时间内每半小时
0 0 10,14,16 * * ?
每天上午10点,下午2点,4点
0 0 12 ? * WED
表示每个星期三中午12点
0 0 17 ? * TUES,THUR,SAT
每周二、四、六下午五点
0 10,44 14 ? 3 WED
每年三月的星期三的下午2:10和2:44触发
0 15 10 ? * MON-FRI
周一至周五的上午10:15触发
0 0 23 L * ?
每月最后一天23点执行一次
0 15 10 L * ?
每月最后一日的上午10:15触发
0 15 10 ? * 6L
每月的最后一个星期五上午10:15触发
0 15 10 * * ? 2005
2005年的每天上午10:15触发
0 15 10 ? * 6L 2002-2005
2002年至2005年的每月的最后一个星期五上午10:15触发
0 15 10 ? * 6#3
每月的第三个星期五上午10:15触发
参考:
springboot2.3.7集成定时任务SchedulingConfigurer
spring - @schedule定时任务器
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。