springboot自带的定时任务和quartz比较

简述

springboot的目的就是为了简化开发,所以我们使用自带的定时任务会非常简单,只需要加注解@Schedule就可以了,那么quartz又如何呢,由于quartz的功能
很强大,当然设计和实现就会复杂,我们使用也会相对复杂。虽然quartz使用复杂,但是我们却不能说quartz不好,两个都支持cron的语法,但是schedule不支
持持久化,而且在复杂功能面前,schedule是完全不够看的。

schedule的简单使用

第一步,也是最重要的步骤就是在启动类上加 @EnableScheduling 注解。没有加上的话不会运行报错,但是不会执行。

然后我们写两个简单的任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class PlayScheduleService {

private static final Logger LOG = LoggerFactory.getLogger(PlayScheduleService.class);

@Scheduled(cron = "*/10 * * * * ?")
public void playMusic(){
LOG.error("music is playing!");
}

@Scheduled(cron = "*/10 * * * * ?")
public void pauseMusic(){
LOG.error("music is pausing!");
}
}

然后我们可以看一下结果:

1
2
3
4
2020-05-21 18:59:40.000 ERROR 8980 --- [   scheduling-1] c.l.w.l.service.PlayScheduleService      : music is playing!
2020-05-21 18:59:40.000 ERROR 8980 --- [ scheduling-1] c.l.w.l.service.PlayScheduleService : music is pausing!
2020-05-21 18:59:50.001 ERROR 8980 --- [ scheduling-1] c.l.w.l.service.PlayScheduleService : music is playing!
2020-05-21 18:59:50.001 ERROR 8980 --- [ scheduling-1] c.l.w.l.service.PlayScheduleService : music is pausing!

我们能看见执行这两个任务的都是单线程。所以是顺序执行的。如果两个任务是有相关性的话是没问题的,但是两个没有相关的任务就出现问题了,因为第二个任务完全没有必要等
到第一个任务执行完毕后才执行。

schedule改进

如果我们需要让两个任务并发执行,那么需要在任务方法上面再添加一个注解 @Async 。当然重要的也是在启动类上加 @EnableAsync

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Service
public class PlayScheduleService {

private static final Logger LOG = LoggerFactory.getLogger(PlayScheduleService.class);

@Async
@Scheduled(cron = "*/10 * * * * ?")
public void playMusic(){
LOG.error("music is playing!");
}

@Async
@Scheduled(cron = "*/10 * * * * ?")
public void pauseMusic(){
LOG.error("music is pausing!");
}
}

结果:

1
2
3
4
5
6
2020-05-21 19:30:40.006 ERROR 5388 --- [         task-2] c.l.w.l.service.PlayScheduleService      : music is pausing!
2020-05-21 19:30:40.006 ERROR 5388 --- [ task-1] c.l.w.l.service.PlayScheduleService : music is playing!
2020-05-21 19:30:50.002 ERROR 5388 --- [ task-3] c.l.w.l.service.PlayScheduleService : music is playing!
2020-05-21 19:30:50.002 ERROR 5388 --- [ task-4] c.l.w.l.service.PlayScheduleService : music is pausing!
2020-05-21 19:31:00.002 ERROR 5388 --- [ task-5] c.l.w.l.service.PlayScheduleService : music is playing!
2020-05-21 19:31:00.002 ERROR 5388 --- [ task-6] c.l.w.l.service.PlayScheduleService : music is pausing!

线程池方式

要想并发执行,其实就是开线程来执行任务。所以我们可以使用线程池的方式来并发执行。

首先写一个定时任务的线程池配置类,需要实现SchedulingConfigurer接口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {

@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
}

@Bean
public Executor taskExecutor(){
return Executors.newScheduledThreadPool(10);
}

}

然后任务写法就和第一个是一样的。结果:

1
2
3
4
2020-05-21 21:33:10.002 ERROR 10696 --- [pool-1-thread-2] c.l.w.l.service.PlayScheduleService      : music is playing!44
2020-05-21 21:33:10.002 ERROR 10696 --- [pool-1-thread-1] c.l.w.l.service.PlayScheduleService : music is pausing!43
2020-05-21 21:33:20.002 ERROR 10696 --- [pool-1-thread-2] c.l.w.l.service.PlayScheduleService : music is playing!44
2020-05-21 21:33:20.002 ERROR 10696 --- [pool-1-thread-1] c.l.w.l.service.PlayScheduleService : music is pausing!43

使用quartz

springboot使用quartz有集成框架的包,由于我是用的gradle,所以gradle的引用:

1
implementation 'org.springframework.boot:spring-boot-starter-quartz'