每周一更的收藏夹吃灰系列又一度提上日程,今晚分享点啥好嘞,哦嚯,有主意了,那还请小伙伴们移目下方吧,"线程池启动执行定时任务"新鲜出炉啦,赶紧趁热吃。

本文背景:

最近接手了一老项目,搁置了有一段时间,现在要我进行项目迭代,也就是二次开发,然后有遇到这么个问题,"就是在项目中设置了定时任务之后 , 发现存在多个定时(周期)任务中总是有个别任务不执行",经过一番折腾之后 , 原来是spring提供的定时器任务scheduled-tasks默认配置是单线程串行执行的。就是说:即在当前时间点之内,如果同时有两个定时任务需要执行的时候, 排在第二个的任务就必须等待第一个任务执行完毕执行才能正常运行。如果第一个任务耗时较久的话 , 就会造成第二个任务不能及时执行。这样就很可能由于任务执行失败导致效性带来一系列问题,后果可想而知,而在实际项目中 , 我们也往往希望这些定时任务是"各干各的" , 而不是排队执行,做到如何并行化?这个问题想必大家都已经浮现在脑海中了。

有小伙伴可能立马就想到了@Async和@EnableAsync,采用异步的方式去处理不就好了,配置不同的线程去执行,思路是对的,但还是略微带点瑕疵,反问:"假如任务A的任务执行时间大于任务调度周期时间的话",会发生什么?很有可能上一个任务未执行完,下一个任务就又开始执行,这种风险带来的影响也很大吧,首先就是定时任务时效性问题,大家说这个怎么规避,显然不是很好,那么有比较适合解决该任务串行化的好方案么,阿柴:"怎么会没有,铁子接着往下看"。

所以最好的方式就是采用多线程,自己控制线程池的数量,有几个任务控制起几个线程,使每个定时任务都在不同的线程上执行,彼此的执行次序和执行时间也都互不影响。

那么阿柴,怎么实现呢?这是个大问题......

接下来,柴兄弟就来教你,学不废请顺着网线来捶我好伐!今晚就算是熬通宵也得把你们教废咯,包教包会,有手就行。

如果觉得这篇文章对你们有所帮助,还请不忘在文章的左下角,直接pia的一下点亮它 up up up!!!若是我,不用犹豫直接进我的收藏夹吃灰去吧!不管以后用不用的上,先吃上灰再说,哈哈哈哈哈嗝~

 1、线程池配置:

SchedulingConfig.java

package com.system.xiaoma.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;/*** 使用自定义的线程池执行异步任务 , 并设置定时任务的异步处理* @author luoyong* @since 2021-05-15*/
@Slf4j
@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "scheduling", name = "enabled", havingValue = "true")
public class SchedulingConfig implements SchedulingConfigurer, AsyncConfigurer {/*** 使用线程池执行定时任务** @param taskRegistrar 注册器*/@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {// 获取线程池TaskScheduler taskScheduler = taskScheduler();// 设置执行定时任务的线程池taskRegistrar.setTaskScheduler(taskScheduler);}/*** 配置一个线程池用于执行定时任务*/@Bean(destroyMethod = "shutdown")public ThreadPoolTaskScheduler taskScheduler() {ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();scheduler.setPoolSize(5);scheduler.setThreadNamePrefix("server-assisted-guard-");scheduler.setAwaitTerminationSeconds(60);scheduler.setWaitForTasksToCompleteOnShutdown(true);return scheduler;}@Overridepublic AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {return (throwable, method, objects) -> {log.error("异步任务执行出现异常, message {}, method {}, params {}", throwable, method, objects);};}}

 2、定时配置

application.properties

###定时器开关 true启动/false关闭定时任务
scheduling.enabled=true###清除日志定时任务时间配置,默认值每个五分钟执行一次
xiaoma.log.clear-task-cron=0 0/5 * * * ?
# 日志保留时间,单位天,默认值30
xiaoma.log.log-timeout=30

3、实例演示:

LogInfoServiceImpl.java

/*** 定时任务清除日志表3个月前的数据* 演示:每五分钟执行一次* 注意: 定时方法不需要任何参数,并且返回类型为 void*/
@Scheduled(cron = "${xiaoma.log.clear-task-cron:0 0/5 * * * ? }")
public void clear() {log.info("开始执行日志清理定时任务");// 获取当前时间Calendar calendar = Calendar.getInstance();// 当前时间减去日志保留时间calendar.add(Calendar.DAY_OF_MONTH, -logTimeOut);logInfoMapper.clear(calendar.getTime());log.info("日志清理定时任务执行成功");
}

LogInfoMapper.java

/*** 清除指定日期之前的日志** @param date 时间*/
void clear(Date date);

LogInfoMapper.xml

<!-- 清除日志 -->
<delete id="clear"><![CDATA[delete from log_info where create_time<#{date}]]>
</delete>

于是在SpringBoot中自定义线程池,执行异步任务 , 并设置定时任务的异步处理;

我设置的是时隔五分钟,静待五分钟;

看下控制台输出打印;好家伙,是我想要看到的结果。

总结: 定时删除日志任务肯定是起效了;

但是阿柴啊,这也就起一定时任务啊,谁不会这啊,任务并行执行呢?......

很多小伙伴看到这肯定有些不耐烦了,别急别急,好戏还在后头呢,接着往下看~


那接下来,就再做个试验:验证启动两个在同一节点的定时任务(clear1和clear2),看看两定时任务到底是异步执行还是串行执行?

ps:由于是测试,就设置两任务都按每一分钟执行一次吧。

预期效果,应该两任务都同时打印定时任务开始,随后再执行定时任务结束!这逻辑才是对的,静候佳音~

@Scheduled(cron = "${xiaoma.log.clear-task-cron:0 0/1 * * * ? }")
public void clear1() {log.info("定时任务一开始");// 获取当前时间Calendar calendar = Calendar.getInstance();// 当前时间减去日志保留时间calendar.add(Calendar.DAY_OF_MONTH, -logTimeOut);logInfoMapper.clear(calendar.getTime());log.info("定时任务一结束");
}@Scheduled(cron = "${xiaoma.log.clear-task-cron:0 0/1 * * * ? }")
public void clear2() {log.info("定时任务二开始");// 获取当前时间Calendar calendar = Calendar.getInstance();// 当前时间减去日志保留时间calendar.add(Calendar.DAY_OF_MONTH, -logTimeOut);logInfoMapper.clear(calendar.getTime());log.info("定时任务二结束");
}

接下来,就是见证奇迹的时候啦!噔噔噔~~

总结:通过控制台打印信息可以看到每个定时任务都在不同的线程上执行,彼此的执行次序和执行时间也互不影响,说明配置生效了,成功异步执行。

另外,集群版本如果要使用@Scheduled的话,需要加分布式锁来控制,或者直接用分布式定时任务Elasticjob或者xxl-job等。


热文推荐:

收藏夹吃灰系列(一):你一定没用过的代码生成工具,好不好用你们说了算

收藏夹吃灰系列(二):教小学妹如何通过代码实现Swagger在线接口文档转word文档!教完后...

收藏夹吃灰系列(三):你一定没用过的MySQL数据库表结构文档生成器,用完后相信你一定会点赞三连的!


为了帮助更多小白从零打造java开发工程师,特地从CSDN官方那讨来了一套 《Java 工程师学习成长知识图谱》

官方出品必属精品!有兴趣的小伙伴可以了解一下!特价优惠,限时限量,抓紧时间哦~


附:cron规则在线教学

1、表达式:{秒数} {分钟} {小时} {日期} {月份} {星期} {年份(可为空)}

2、占位符解释:

字段

允许值

允许的特殊字符

秒数

0~59

- , * /

分钟

0~59

- , * /

小时

0~23

- , * /

日期

1~31,需注意每个月的天数

- , * / ? L W C

月份

1~12或JAN-DEC

- , * /

星期

1~7或SUN-SAT

- , * / ? L C #

年份

1970~2099,可为空

- , * /

星期:1代表星期天(一星期的第一天),7代表星期六(一星期的最后一天)。

3、特殊字符:

  • -代表在指定的范围内触发,比如"25-45"代表从25秒开始触发到45秒结束触发,每隔1秒触发1次
  • ,代表在指定的秒数触发,比如"0,15,45"代表0秒、15秒和45秒时触发任务
  • *代表每隔1秒钟触发
  • /代表触发步进(step),斜杠前面的值代表初始值,后面的值代表偏移量
    • "0/20"或"/20":从0秒钟开始,每隔20秒钟触发1次,即0秒触发1次,20秒触发1次,40秒触发1次
    • "5/20":5秒触发1次,25秒触发1次,45秒触发1次
    • "10-45/20":在[10,45]内步进20秒命中的时间点触发,即10秒触发1次,30秒触发1次
  • ?代表日期和星期互斥,即把日期占位符标为问好则代表是指定星期触发,把星期占位符标为问好则代表是指定日期触发
  • L(Last)若用在日期上代表这个月最后一天;若用在星期上代表这周的最后一天即星期六;若用在星期上并且配合数字如"5L"代表这个月的最后一个星期四触发
  • W(Weekday)只用在日期上,代表最接近指定天的工作日(周一到周五),比如"15W":最接近这个月第15天的工作日
    • 如果这个月第15天是周六,那么触发器将会在这个月第14天即周五触发
    • 如果这个月第15天是周日,那么触发器将会在这个月第16天即周一触发
    • 如果这个月第15天是周二,那么就在触发器这天触发
    • 只会在当前月计算值,不会越过当前月
    • "LW"代表这个月的最后一个工作日
  • #只用在星期上,代表这个月的第几个周几,比如"6#3"指这个月第3个周五(6指周五,3指第3个),如果指定的日期不存在,触发器就不会触发
  • C(Calendar)代表依靠一个指定的“日历”,没有“日历”关联,则等价于所有包含的“日历”
    • 用在日期上"5C"表示关联“日历”中第一天,或者这个月开始的第一天的后5天
    • 用在星期上"1C"表示关联“日历”中第一天,或者星期的第一天的后1天,也就是周日的后一天(周一)

4、举例:

  • "0 * 21-23,0-5 * * ?" 晚上9点到第二天凌晨5点,每一分钟执行一次(跨天执行)
  • "0 * 17-23/2,8 * * ?" 17点到23点每隔两小时和上午8点,每一分钟执行一次
  • "0 0 12 * * ?" 每天中午12点触发
  • "0 15 10 ? * *" 每天上午10:15触发
  • "0 15 10 * * ?" 每天上午10:15触发
  • "0 15 10 * * ? *" 每天上午10:15触发
  • "0 15 10 * * ? 2005" 2005年的每天上午10:15触发
  • "0 * 14 * * ?" 在每天下午2点到下午2:59期间的每1分钟触发
  • "0 0/5 14 * * ?" 在每天下午2点到下午2:55期间的每5分钟触发
  • "0 0/5 14,18 * * ?" 在每天下午2点到2:55期间和下午6点到6:55期间的每5分钟触发
  • "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触发
  • "0 15 10 ? * 6#3" 每月的第三个星期五上午10:15触发

❤如果文章对您有所帮助,就请在文章末尾的左下角把大拇指点亮吧!(#^.^#);

❤如果喜欢阿柴柴(笔名)分享的文章,就请给阿柴柴个关注吧!(๑′ᴗ‵๑)づ╭❤~;

❤对文章有任何问题欢迎小伙伴们下方留言或者入群探讨【群号:708072830】;

❤鉴于个人经验有限,所有观点及技术研点,如有异议,请直接回复参与讨论(请勿发表攻击言论,谢谢);

❤版权声明:本文为博主原创文章,转载请附上原文出处链接和本文声明,版权所有,盗版必究!(*^▽^*).

收藏夹吃灰系列(四):谁说Spring提供的@Scheduled定时不好用?师妹看了直呼叫好!相关推荐

  1. 我的 Spark 3.1.1 之旅【收藏夹吃灰系列】

    点击蓝色"有关SQL"关注我哟 加个"星标",天天与10000人一起快乐成长 图 | 榖依米 大数据三部曲终于完成了: 我的 Hadoop 3.2.2 之旅 [ ...

  2. 收藏夹吃灰系列(九):实现图片倒排序并取出时间最近的那一张!并下载到本地 | 超级详细,建议收藏!

    需求很简单 ,就是取出时间最新的那张并下载到本地! 实现:倒排序,然后取第一张即可! public void imageDownload(String path) {FileInputStream i ...

  3. 计算机网络八股文背诵版(收藏夹吃灰系列)

    一份计算机网络的八股文,给各位准备春招的小伙伴献上,不多说,开背!! 简述OSI七层协议 OSI七层协议包括:物理层,数据链路层,网络层,运输层,会话层,表示层, 应用层 简述TCP/IP五层协议 T ...

  4. 收藏夹吃灰系列(二):教小师妹通过代码实现Swagger在线接口文档转word文档!教完后...?

    话不多说,工具源码直接分享给大家吧: 如果最后觉得该代码生成器对你有所帮助,请不要吝啬你的赞,直接pia的点亮就完了啦,up up up!!! 如下就是全码,拿走!不谢!!助你趁早解放双手! 本地sw ...

  5. 【Gephi】初学者教程(一)「一步一步教你怎么画图」「值得放进收藏夹吃灰系列」

    前言 由于最近博主日常接任务帮人画图,而最近的状况大家也知道-远程画着画着觉得双方在图的结构.调色等等诸多方面会有很多歧义,博主理解的往往与客户所言有些许偏差-当然这其中也是包括有客户并未接触过gep ...

  6. 科研必备网站(收藏夹吃灰系列)

    分享一些科研必备的网站,也供自己找不到网址时检索.V2022年3月16日 1. 在线绘图网站 BioLadder-生物信息在线分析可视化云平台(https://www.bioladder.cn/) M ...

  7. 收藏夹吃灰系列(十):一篇文教你如何快速实现乐观锁机制及适用场景 | 超级详细,建议收藏!

    大家好,我是bug菌~~ Hi ,小伙伴们,我们又见面啦!先给大家说声抱歉,距离上一篇发文已经时隔快两个月了,至于为什么不及时更文了呢?有小伙伴可能就会猜,要么是太忙要么就是转移到其他的博客上了... ...

  8. Git使用 从入门到入土 收藏吃灰系列(四) Git工作原理

    文章目录 一.前言 一.Git基本理论(核心) 1.1工作区 1.2工作流程 一.前言 参考安装Git 详细安装教程 参考视频B站 Git最新教程通俗易懂,这个有点长,感觉讲的精华不多 参考视频『Gi ...

  9. STM32夺命100问,收藏夹吃灰走起~

    1.AHB系统总线分为APB1(36MHz)和APB2(72MHz),其中2>1,意思是APB2接高速设备. 2.Stm32f10x.h相当于reg52.h(里面有基本的位操作定义),另一个为s ...

  10. 七个开源的 SpringBoot 前后端分离项目,Star过千,快去收藏夹吃灰吧!

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 微信公众号:江南一点雨 前后端分离已经在慢慢走进各公司的技 ...

最新文章

  1. Rust和C / C ++的跨语言链接时间优化LTO
  2. DLR学习笔记(01)
  3. mysql 5.5.37 my.cnf,linux安装最新mysql5.5,my.cnf找不到解决办法
  4. 万国数据联合阿里云发布混合云系列产品 助力企业落地云端
  5. 数据库技术基础:查询优化相关知识笔记
  6. ZJU cluster
  7. 使用idea上传项目到gitHub
  8. Java动态so库修改,Adnroid so文件动态调试技巧
  9. 从零开始学安全(七)●Linux基础命令学习笔记
  10. openwrt qca9886 ath10k只能连32台设备问题解决
  11. 美团在O2O场景下的广告营销
  12. 双麦降噪远场 拾音模块 : AN-93
  13. ThinkPad E14 Slim 使用报告
  14. asterisk cdr mysql_asterisk cdr写入mysql为空的解决办法
  15. 做软件测试有前途么?
  16. 实时网速监测app_实时网速-实时网速app安卓版下载v1.0-我爱秘籍
  17. 基于浮云E绘图源码定制开发网络状态图(拓扑图),关联业务对象,并动态更新
  18. VMware虚拟机不能全屏的解决方法
  19. 谷歌浏览器访问地址报错备忘
  20. 功率因数(PF)与总谐波失真(THD)在原理层面上的关系

热门文章

  1. 【CV系列】昼夜图像区分算法
  2. 项目管理论坛_活动预告|2019年“VUCA时代项目管理与项目治理”论坛通知
  3. 10 Habits of All Successful People 成功人士的10个习惯
  4. 重庆金域 :新系统成功上线!重庆金域第一份新系统的报告单2017年9月21日13:00正式发出
  5. 计算机休眠后无法连接无线网络,笔记本Win7系统唤醒休眠模式后无线无法自动连接怎么办...
  6. 快速学习-常见DOS命令精讲
  7. brain segmentation调研--Brain Parcellation as a Pretext Tas
  8. Linux键盘输入读取
  9. 一个链表L 一个链表P 包含升序排列的整数 操作PrintLots(L,P)将打印L中那些由P所指定的位置上的元素
  10. Senparc.Weixin.MP SDK 微信公众平台开发教程(五):使用Senparc.Weixin.MP SDK