使用Spring定时任务@scheduled需要注意的问题

在Spring管理的javaWeb项目中,因为要使用到定时任务,可以使用了Spring的@Scheduled来实现定时任务功能,使用起来也很方便,只需要一个注解就可以轻松搞定定时任务开发,但是当开发完之后部署之后,偶现定时任务没有根据预定时间周期设置来触发执行,于是开始排查问题出在哪。我的需求是我需要两个不同的定时任务,都是每隔一分钟进行触发去查询业务表中满足时间条件的数据,根据业务数据的时间和当前系统时间做比对,对满足条件的数据来执行相应的业务操作。方法如下:

  1. 踩坑一: 当项目中有多个@scheduled标记的定时可能由前面的定时任务阻塞造成后面的定时任务不执行;

在需求实现中,我会每隔一分钟将当前系统时间与业务数据中记录的需要触发事件的时间做一次对比,当系统时间与业务表的时间的差值在一分钟内,便触发方法中业务操作,自测两个定时任务的触发都没有问题,当到测试环境时,就会出现定时任务没有按照业务设定去触发。

经过排查发现@scheduled定时执行任务的时候是在一个单线程中,如果程序中同时有多个任务在执行,如果其中一个任务执行时间过长,则有可能会导致其他后续任务被阻塞直到该任务执行完成,也就是会造成一些任务无法定时执行的错觉。无论@scheduled是用在一个类的多个方法还是用在多个类中的方法,默认都是单线程的。因此我判定应该是我两个定时任务中,前一个定时任务执行时,因为方法中有发送消息等操作造成出现阻塞,造成第二个定时任务延时执行了,打破了每分钟执行的设定,本应该执行的业务系统操作因为定时任务阻塞而造成时间不匹配未执行;

解决方法:可以将定时任务中的操作使用多线程异步执行,避免因为一个定时任务阻塞影响另外一个执行。也可以在类上添加@EnableAsync注解,在每个有@scheduled注解的定时方法上添加@Async注解,将定时任务变为异步执行。

  1. 踩坑二:修改服务器时间时会导致@scheduled定时任务不执行;

在开发环境自测时,将部署应用程序的服务器时间往前调了之后,发现本该触发执行的定时任务死活不执行;

经过查资料发现当使用@scheduled 开启定时任务时,java程序的jvm启动之后会记录系统时间,然后JVM根据CPU ticks自己来算时间,此时获取的是定时任务的基准时间。如果此时将系统时间进行了修改,当Spring会将之前获取的基准时间与当下获取的系统时间进行比对时,就会造成Spring内部定时任务失效。因为此时系统时间发生变化了,不会触发定时任务。

解决办法:

  1. 当每次修改系统时间时,需要将程序进行重启;
  2. 如果需要修改系统时间,定时任务受影响,可以使用其他的定时任务框架,也可以使用java的ScheduledThreadPoolExecutor来自己实现,它任务的调度是基于相对时间的,定时任务不会因为系统时间改变而改变。

另外:使用@scheduled来定时任务时,需要确保在配置类上添加了@EnableScheduling注解,使用@Scheduled注解的定时任务才能够被正常执行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值