也就是说,内置的三个调度器类型底层都依赖于JUC调度线程池ScheduledThreadPoolExecutor。这里分析一下顶层接口org.springframework.scheduling.TaskScheduler提供的功能(笔者已经把功能一致的default方法暂时移除):
// 省略一些功能一致的default方法 public interface TaskScheduler { // 调度一个任务,通过触发器实例指定触发时间周期 ScheduledFuture<?> schedule(Runnable task, Trigger trigger); // 指定起始时间调度一个任务 - 单次执行 ScheduledFuture<?> schedule(Runnable task, Date startTime); // 指定固定频率调度一个任务,period的单位是毫秒 ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period); // 指定起始时间和固定频率调度一个任务,period的单位是毫秒 ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period); // 指定固定延迟间隔调度一个任务,delay的单位是毫秒 ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, long delay); // 指定起始时间和固定延迟间隔调度一个任务,delay的单位是毫秒 ScheduledFuture<?> scheduleWithFixedDelay(Runnable task, Date startTime, long delay); } Task的分类Scheduling模块中支持不同类型的任务,主要包括下面的3种(解析的优先顺序也是如下):
Cron表达式任务,支持通过Cron表达式配置执行的周期,对应的任务类型为org.springframework.scheduling.config.CronTask。
固定延迟间隔任务,也就是上一轮执行完毕后间隔固定周期再执行本轮,依次类推,对应的的任务类型为org.springframework.scheduling.config.FixedDelayTask。
固定频率任务,基于固定的间隔时间执行,不会理会上一轮是否执行完毕本轮会照样执行,对应的的任务类型为org.springframework.scheduling.config.FixedRateTask。
关于这几类Task,举几个简单的例子。CronTask是通过cron表达式指定执行周期的,并且不支持延迟执行,可以使用特殊字符-禁用任务执行:
// 注解声明式使用 - 每五秒执行一次,不支持initialDelay @Scheduled(cron = "*/5 * * * * ?") public void processTask(){ } // 注解声明式使用 - 禁止任务执行 @Scheduled(cron = "-") public void processTask(){ } // 编程式使用 public class Tasks { static DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws Exception { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); CronTask cronTask = new CronTask(() -> { System.out.println(String.format("[%s] - CronTask触发...", F.format(LocalDateTime.now()))); }, "*/5 * * * * ?"); taskScheduler.schedule(cronTask.getRunnable(),cronTask.getTrigger()); Thread.sleep(Integer.MAX_VALUE); } } // 某次执行输出结果 [2020-03-16 01:07:00] - CronTask触发... [2020-03-16 01:07:05] - CronTask触发... ......FixedDelayTask需要配置延迟间隔值(fixedDelay或者fixedDelayString)和可选的起始延迟执行时间(initialDelay或者initialDelayString),这里注意一点是fixedDelayString和initialDelayString都支持从EmbeddedValueResolver(简单理解为配置文件的属性处理器)读取和Duration(例如P2D就是parses as 2 days,表示86400秒)支持格式的解析:
// 注解声明式使用 - 延迟一秒开始执行,延迟间隔为5秒 @Scheduled(fixedDelay = 5000, initialDelay = 1000) public void process(){ } // 注解声明式使用 - spring-boot配置文件中process.task.fixedDelay=5000 process.task.initialDelay=1000 @Scheduled(fixedDelayString = "${process.task.fixedDelay}", initialDelayString = "${process.task.initialDelay}") public void process(){ } // 编程式使用 public class Tasks { static DateTimeFormatter F = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); public static void main(String[] args) throws Exception { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); taskScheduler.initialize(); FixedDelayTask fixedDelayTask = new FixedDelayTask(() -> { System.out.println(String.format("[%s] - FixedDelayTask触发...", F.format(LocalDateTime.now()))); }, 5000, 1000); Date startTime = new Date(System.currentTimeMillis() + fixedDelayTask.getInitialDelay()); taskScheduler.scheduleWithFixedDelay(fixedDelayTask.getRunnable(), startTime, fixedDelayTask.getInterval()); Thread.sleep(Integer.MAX_VALUE); } } // 某次执行输出结果 [2020-03-16 01:06:12] - FixedDelayTask触发... [2020-03-16 01:06:17] - FixedDelayTask触发... ......