我终于会写 Java 的定时任务了!( 三 )


@Slf4jpublic class ScheduledExecutorServiceDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {testFixedDelay();}public static void testFixedDelay() {ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();log.info("1秒后开始执行任务,此刻时间---{}", LocalDateTime.now());// 任务完成后间隔4秒开始执行下一次任务scheduledExecutorService.scheduleWithFixedDelay(() -> {log.info("任务开始---{}", LocalDateTime.now());try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}log.info("任务结束---{}", LocalDateTime.now());}, 1000, 4000, TimeUnit.MILLISECONDS);}}通过 Thread.sleep(2000) 模拟任务执行了 2 秒的时间 , 控制台输出如下:
14:20:31.352 [main] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 1秒后开始执行任务,此刻时间---2022-10-25T14:20:31.35114:20:32.370 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:20:32.37014:20:34.371 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:20:34.37114:20:38.379 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:20:38.37914:20:40.381 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:20:40.381可以看到,第一次任务结束的时间是 14:20:34 ,即第 34 秒,下一次执行的时间是 14:17:38,即第 38 秒,这个过程经过了 4 秒钟,这就是 scheduleWithFixedDelay() 方法的效果 。
以上就是 ScheduledExecutorService 实现的定时任务,接下来看看 Spring 提供的 。
Spring 提供的定时任务Spring 提供了 @EnableScheduling@Scheduled 这两个注解来实现定时任务 。
我们可以编写一个类,加上 @Component 让 Spring 来管理这个 Bean(当然,也可以用 @Configuration 注解),加上 @EnableScheduling 表明该 Bean 具有可开启定时任务的功能 。
在这个普通的类中编写方法,你可以让你写的方法成为一个定时任务,只需在方法上加上 @Scheduled 注解就可以了,就是这么简单!
还有一个就是 cron 表达式 需要学习,这个表达式可以表明这个方法何时执行 。
下面是一个简单的定时任务:
@Slf4j@Component@EnableSchedulingpublic class TaskDemo {@Scheduled(cron = "*/1 * * * * ?")public void printTime() throws InterruptedException {log.info("此刻时间 {}", LocalDateTime.now());}}cron 表达式有 6 位,是必须的,从左到右分别表示:秒、分、时、日、月、周
当然也有可能是 7 位,那么最后一位就是年(一般省略不写):秒、分、时、日、月、周、年
取值说明:正常认识,秒分都是 0 - 59 , 时则是 0 - 23,日则是 1 - 31,月则是 1-12,周则是 1 - 7 。年则只有 1970 - 2099
每一位都可以用数字表示 , 当然还可以用一些特殊字符表示 , 比如上面出现的 */1 * * * * ?  , 第 1 位的 */1 表示任意秒每隔1秒 , 第 2 位的 * 表示任意分钟 , 以此类推 。

详细可参考这里:简书-Cron表达式的详细用法
Cron 生成工具:https://cron.qqe2.com/
上面的代码运行之后,控制台输出:
2022-10-25 14:26:22.013INFO 18304 --- [scheduling-1] cn.god23bin.demo.task.TaskDemo: 此刻时间 2022-10-25T14:26:22.0132022-10-25 14:26:23.010INFO 18304 --- [scheduling-1] cn.god23bin.demo.task.TaskDemo: 此刻时间 2022-10-25T14:26:23.0102022-10-25 14:26:24.011INFO 18304 --- [scheduling-1] cn.god23bin.demo.task.TaskDemo: 此刻时间 2022-10-25T14:26:24.0112022-10-25 14:26:25.011INFO 18304 --- [scheduling-1] cn.god23bin.demo.task.TaskDemo: 此刻时间 2022-10-25T14:26:25.011可以看到,确实是每隔 1 秒执行一次 printTime() 这个定时任务 。
@Scheduled 的另外两个属性@Scheduled 注解除了 cron 这个属性外,还有 fixedRate 属性和 fixedDelay 属性,同理,就是固定频率触发定时任务和固定延迟触发定时任务
fixedRate@Slf4j@Component@EnableSchedulingpublic class TaskDemo {/*** 当前任务执行到下一个任务开始的时间(固定频率开始执行一个任务,每5秒执行),都是单线程处理的**/@Scheduled(fixedRate = 5000)public void printTime1() throws InterruptedException {log.info("任务开始------- {}", LocalDateTime.now());Thread.sleep(1000);log.info("任务完成------- {}", LocalDateTime.now());}}

推荐阅读