正文
首先,文中使用的是 springboot的2.7.0
版本。
定时任务用法-单线程
定时任务的配置很简单,只需要配置声明@EnableScheduling
就可以了,然后就可以使用了,大概就是下面的样子:
1 |
|
注解版本-cron表达式
新建一个类,使用Scheduled注解的cron,这里需要对cron了解,不过网上有在线版生成cron的网站。
1 |
|
执行结果:
1 |
|
从执行结果可以看出来,执行时间是十秒钟一次,但是设置的又是五秒钟执行一次,原因是执行任务会休眠六秒钟,执行下一次任务时,任务还在休眠,所以中间那一次会被放弃。 至此,一个springboot自带的简单的定时任务就创建好了,可以执行了。
注解版本-fixedDelay与fixedRate
创建两个定时任务,分别使用fixedDelay与fixedRate,需要注意的是两个定时任务都加了线程睡眠六秒钟。
fixedDelay
先来看fixedDelay, 这个参数是在任务执行完成后,在进行时间延迟,具体例子如下:
1 |
|
执行结果:
1 |
|
可以看到每次任务的间隔时间都是11秒,也就是任务执行了6秒加上原本设置的五秒,所以总共间隔是一秒。也就是fixedDelay是在任务执行完成后才开始计算设置的间隔时间。
fixedRate
例子如下:
1 |
|
执行结果:
1 |
|
从执行结果中可以看到,fixedRate的计算时间是从任务开始执行时计算的,若任务执行时间超过了设置时间,则下一次会在任务完成后立即执行。
从上面fixedRate和fixedDelay可以看出区别,前者是从任务开始时计算设置的时间,后者是任务执行完成后再计算设置时间。
实现SchedulingConfigurer接口
定时任务也可以使用实现SchedulingConfigurer接口来实现,代码如下:
1 |
|
执行结果:
1 |
|
从执行结果可以看出,和cron表达式是一样的,当任务执行时间超过了设置时间,那么在执行时间以内的任务都不会执行,直到任务执行完才会执行下一次。
多线程与单线程区别
在上面的案例中,所有的定时任务都是用的一个线程在执行,因为sprin中默认对线程池配置了一个线程,如果只有一个简单的定时任务,或者定时任务之间没有交叉点的话,没啥影响。 但是当定时任务之间有时间交叉点,那么单线程的话就会受到影响了。 先来看看单线程的影响: 测试代码如下:
1 |
|
未配置多线程的执行结果:
1 |
|
从结果可以看出,单线程的情况下,每秒执行一次的任务并没有按预想的执行,被每五秒执行的任务影响到了,下面来配置线程池有多个线程。
如果使用@Scheduled注解的话,就在配置文件添加配置就可以了,简单配置如下:
1 |
|
还是上面部分代码, 只是配置了多线程,执行结果如下:
1 |
|
从执行结果可以看出来,两个定时任务之间是互不影响的。自己执行自己的。 但是需要注意的是,如果定时任务执行时间超过了设置的时间,那么在任务执行期间的重复执行的任务是会被舍弃的,不管是否配置了线程池。也就是定时任务只会影响到自己的。
如果是使用的实现SchedulingConfigurer接口的定时任务,上面的配置是不生效的,反而会造成@Scheduled注解的定时任务也只有一个线程执行。 而如果要使实现SchedulingConfigurer接口的定时任务用多线程跑的话,需要在实现SchedulingConfigurer接口的类中手动设置线程池,具体实现如下:
1 |
|
这里需要注意的是,线程池需要自己定义,这里为了方便,都定义到一个类了。
最后
使用定时任务时:
- @EnableScheduling 这样的注解,项目中配置到一个地方就行了,不用每个定时任务类或者配置类都去添加这个注解。
- 定时任务尽量使用多线程,不要使用默认配置的单线程。当然甚至还可以使用异步注解来将定时任务变成多线程执行。