一、静态:基于注解
基于注解@Scheduled默认为单线程,开启多个任务时,任务的执行时机会受上一个任务执行时间的影响。
1、创建定时器
@Configuration
@EnableScheduling //开启定时任务
public class ScheduleTask {
@Scheduled(cron = "0/5 * * * * ?")
//或直接指定时间间隔,例如:5秒
//@Scheduled(fixedRate=5000)
public void task(){
System.out.println("执行静态定时任务"+Thread.currentThread().getName()+"时间"+LocalDateTime.now());
}
}
Cron表达式参数分别表示:
@Scheduled:除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。
启动应用,可以看到控制台打印出如下信息:
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:35.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:40.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:45
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:50.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:15:55
执行静态定时任务pool-10-thread-1时间2019-02-22T11:16:00.001
执行静态定时任务pool-10-thread-1时间2019-02-22T11:16:05.001
显然,使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。
二、动态:基于接口
基于接口(SchedulingConfigurer)
1、导入依赖包:
org.springframework.boot
spring-boot-starter
2.0.4.RELEASE
org.springframework.boot
spring-boot-starter-web
mysql
mysql-connector-java
org.mybatis.spring.boot
mybatis-spring-boot-starter
1.3.1
org.mybatis
mybatis
3.4.5
compile
2、添加数据库记录:
3、创建定时器
数据库准备好数据之后,我们编写定时任务,注意这里添加的是TriggerTask,目的是循环读取我们在数据库设置好的执行周期,以及执行相关定时任务的内容。
@SuppressWarnings("ALL")
@Configuration
@EnableScheduling
public class DynamicScheduleTask implements SchedulingConfigurer {
@Autowired //注入mapper
getCronMapper cronMapper;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(
//添加任务内容
() -> System.out.println("执行动态定时任务"+ LocalDateTime.now().toLocalTime()),
//设置执行周期
triggerContext -> {
//从数据库获取执行周期
String cron = cronMapper.getCron();
//合法性校验
if(StringUtils.isBlank(cron)){
}
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
public interface getCronMapper{
@Select("SELECT cron FROM cron")
String getCron();
}
启动应用后,查看控制台,打印时间是我们预期的每5秒一次
然后打开Navicat ,将执行周期修改为每6秒执行一次
查看控制台,发现执行周期已经改变,并且不需要我们重启应用,十分方便。
注意: 如果在数据库修改时格式出现错误,则定时任务会停止,即使重新修改正确;此时只能重新启动项目才能恢复。
三、多线程定时任务
基于注解设定多线程定时任务
1、创建多线程定时任务
@Controller
@EnableScheduling
@EnableAsync
public class MultithreadScheduleTask {
@Async
@Scheduled(fixedDelay = 1000)
public void first() throws InterruptedException {
System.out.println("第一个任务开始"+ LocalDateTime.now().toLocalTime()+"线程是"+Thread.currentThread().getName());
System.out.println();
Thread.sleep(3000);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second(){
System.out.println("第二个任务开始"+ LocalDateTime.now().toLocalTime()+"线程是"+Thread.currentThread().getName());
System.out.println();
}
}
2、启动测试
启动应用后,查看控制台:
第一个任务开始11:30:18.508线程是SimpleAsyncTaskExecutor-4
第二个任务开始11:30:18.510线程是SimpleAsyncTaskExecutor-5
第一个任务开始11:30:19.508线程是SimpleAsyncTaskExecutor-6
第一个任务开始11:30:20.508线程是SimpleAsyncTaskExecutor-8
第二个任务开始11:30:20.508线程是SimpleAsyncTaskExecutor-7
第一个任务开始11:30:21.509线程是SimpleAsyncTaskExecutor-9
第二个任务开始11:30:22.510线程是SimpleAsyncTaskExecutor-10
从控制台可以看出,第一个定时任务和第二个定时任务互不影响;
并且,由于开启了多线程,第一个任务的执行时间也不受其本身执行时间的限制,所以需要注意可能会出现重复操作导致数据异常。