定时任务启动后修改系统时间造成定时任务失效的问题

由于公司项目的需求,有时候需要更改系统时间,当把系统时间从当前(T1)往未来时间(T2)调整的话没什么问题,但是再从未来时间(T2)往回调整就会造成定时任务挂起的情况。网上也找了很多资料,但是没有什么合适的解决方案,很多文章提供的解决方案就是→重启项目!!!(我竟无言以对)。
然后呢,就自己想了个解决方案,当然只是完成了需求,在性能方面其实不好。希望有更好解决方案的前辈留言指点一下。

定时任务大概分三类:
1.是java自带的Timer+TimerTask
2.是基于注解式的实现 @Scheduled(…)
3.是定时任务框架 如quartz 这样。
本文是使用注解的方式开发的。关于Timer+TimerTask 以及注解式的基础讲解就不再介绍了,网上有很多写的很好的博客需要的童鞋可以去看一下。这里就说下我的解决思路吧。

首先来说,定时任务执行时间的配置有两种:
1.cron表达式(绝对时间)
2.fixedRate(相对时间)
这里简单说一下上述的绝对时间意思是:
cron表达式中会涉及到绝对时间比如:每天凌晨2点执行 。那么它计算执行时间的方式是通过系统时间算出来的,也就是说如果用cron表达式来配置的话那么你更改系统时间就会影响到你的定时任务,举个简单的例子:比如第一次执行任务的时间为9:00,执行间隔为1小时一次;那么下次执行的时间应该是10:00而如果你修改系统时间就可能会造成定时任务的失效;

而fixedRate相对时间的意思是:计算执行时间的方式是根据项目启动的时间来算出来的,是从项目启动时间开始计算的。比如:第一次执行任务的时间为9:00,执行间隔为1小时一次;那么下次执行的时间应该是一个小时以后。也就是说它是通过记录你上次任务执行了多久来判断下次任务的触发时机。它不关心你的系统时间是多少。所以这种方式能够很好的解决我们更改系统时间的需求。

@Scheduled(fixedRate=6000L)//这里表示项目启动后执行一次,然后每间隔6秒钟任务执行一次,
public void run(){
//...任务代码
}
@Scheduled(fixedRate=6000L,initialDelay=6000L)//这里表示项目启动后6秒钟执行一次,然后每隔6秒执行一次。
public void run(){
//...任务代码
}

到这里,已经解决掉一部分问题了!
最关键的部分来了: cron表达式可以配置任意时间,比如刚才提到的:每天两点执行一次任务。 那么此时就遇到问题了,刚才说了fixedRate的判断机制是通过相对时间来确定的,压根和系统时间没半毛钱关系。那么如何来完成这个需求呢。先看下代码:

@Scheduled(fixedRate = 60000L)
public void run(){
	//获取当前系统时间,判断当前系统时间是否为凌晨2点
	SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
	if(!sdf.format(System.currentTimeMillis()).equals("02:00")){
		return;
	}
	...任务代码
}

大致思路就是通过fixedRate的方式来触发定时任务,然后在任务方法中拿到系统时间进行验证,如果不到2点就return出去,这样就实现了功能上行的需求。

这种方法缺陷也很明显,就是每分钟都需要启动一次定时任务,看起来很呆。比较浪费资源,苍蝇再小也是肉哇。 但是对于我当前的项目来说这个需求是非常重要的。浪费点资源也是值得的。
最后,希望有更好解决方案的童鞋或者前辈能够给指点一下。

猜你喜欢

转载自blog.csdn.net/weixin_43141627/article/details/84253470