聊聊项目中定时任务的处理方式

时间:2023-02-06 07:14:08

  一个项目中一般都少不了定时任务,主要用来处理一些特殊的任务,有的是只执行一次的

定时任务,有的是周期循环执行的定时任务。可根据项目需要来选择定时任务类型。自己参与

开发的一个项目中,因为很多定时任务都是需要周期执行的,因此选用按周期循环执行的方式。

比如几分钟重载一次主表数据,重载数据字典表数据,定时更新主表数据状态,定时更新缓存

数据到数据库中的定时任务等等。因此在项目最开始设计的时候,架构人员就考虑使用使用

周期性定时任务来处理各种任务。

  整体的大致思路是在项目启动的时候,立马启动固定的线程数,比如18个线程,然后让

这些线程去轮流执行定时任务,创建方式为Executors.newFixedThreadPool(20)。这种方式是

阿里巴巴的《Java开发手册》中推荐的创建线程的一种方式。创建完线程池后,下一步就是

使用线程对象去定时执行任务,可以传入一些参数,比如延迟启动时间,执行间隔时间,需要

执行的任务对象等等。最后一步最重要的,就是写定时任务处理类,定时任务类需要实现Runnable

接口,然后重写run方法,接下来主要的定时任务逻辑都写在run方法中。

  定时任务类中可能会查询数据库数据,或者是引用其他的service服务类来处理业务逻辑,这时

需要添加一个@Component注解即可将这个类交给Spring统一处理,也能自动注入需要使用的其他类。

自己最近写的一个定时任务也是同样的处理方式。数据的处理流程为,使用定时任务1将符合条件的

A中的数据定时添加到内存中;使用定时任务2将符合要求的表A的数据,按照一定的规则添加到

B中,并且将表B返回的ID添加到redis队列中;使用定时任务3redis队列中获取数据,如果队列

中有数据,则进行后续处理,将表B中的数据按照一定的规则添加到表C。这样整个业务流程都串起来,

用户登录系统后直接查询表C的数据即可。

  自己写好功能后,反反复复地进行测试,发现一些问题,比如定时任务在一个周期内只想时间过长,

还未执行完成,下一次的执行任务又开始执行。这显然是不符合要求的,那怎么解决呢?看过同事以前

写的代码,解决办法为添加分布式锁。自己立马去修复这个问题,对于需要添加分布式锁的两个定时任务

立马添加分布式锁,执行之前先获取锁,如果获取到锁则执行定时任务,没有获取到锁这不执行任务。

经过测试问题解决。第二个问题是,执行时间间隔的问题,本地开发环境只有单个服务器在运行,测试

环境中也只有一台服务器运行,都没问题,可是生产环境上有多台服务器在运行,定时任务的执行时间

就需要从新分配。比如某个定时任务计划是10s执行一次,生产环境有5台,就需要将间隔时间设置

50s执行一次,不然可能出现的问题就是执行频率远远大于10s。因为是多台服务器在同时执行定时

任务,而且开始执行的时间还不一致,所及执行时间间隔需要慎重计算。

  曾经参与开发过的项目中,有的会有一个单独的定时任务项目,用来执行各种可配置的定时任务,

当然这些都是根据具体项目来选用和开发的。以上就是关于定时任务执行的整个设计思路,有其他

更好建议的小伙伴,欢迎留言讨论。