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


所以,任务 B 会每隔 2 秒执行一次 。到这里,我们通过 Timer 实现了定时任务 。下面看看基于多线程的 ScheduledExecutorService 接口 。
ScheduledExecutorServiceScheduledExecutorService 接口位于 java.util.concurrent 包中,是继承 ExecutorService 接口的 。
这个接口有 4 个抽象方法(先了解一下):
public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit);public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit);public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit);从上面的抽象方法可以看到,第一个参数是 Runnable 接口或 Callable 接口,这里就是写任务逻辑的,后面的 delay 也和之前的意思一样,延迟多少时间才开始执行这个定时任务,unit 主要是指定 long 参数的时间单位 。period 也是一样的意思,间隔多少秒(周期)才执行下一次的任务 。

ExecutorService 接口表述了异步执行的机制,并且可以让任务在后台执行 。ExecutorService 接口的实现类有我们知道的 ThreadPoolExecutor (不知道的话,现在就知道啦) 。
基本使用那我们如何获取 ScheduledExecutorService 的实现类?如何使用它实现定时任务?
可以通过 Executors.newSingleThreadScheduledExecutor() 获取其实现类,然后调用 schedule() 方法实现定时任务 。
现在先看一下,如何使用:
@Slf4jpublic class ScheduledExecutorServiceDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {testScheduledExecutorService();}public static void testScheduledExecutorService() throws ExecutionException, InterruptedException {ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();log.info("2秒后开始执行任务,此刻时间---{}", LocalDateTime.now());ScheduledFuture<?> future = scheduledExecutorService.schedule(() -> {log.info("任务开始---{}", LocalDateTime.now());try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}log.info("任务结束---{}", LocalDateTime.now());return "ok";}, 2000, TimeUnit.MILLISECONDS); // 延迟 2 秒后执行log.info("任务执行后 future {}, 时间 {}", future.get(), LocalDateTime.now());}}控制台输出:
14:15:44.510 [main] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 2秒后开始执行任务,此刻时间---2022-10-25T14:15:44.50914:15:46.524 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:15:46.52414:15:48.537 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:15:48.53714:15:48.538 [main] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务执行后 future ok, 时间 2022-10-25T14:15:48.538很明显,这里不是一个定时任务,因为只执行了一次就结束了,所以我们需要调用两外两个来实现,分别是 scheduleAtFixedRate() 方法和 scheduleWithFixedDelay() 方法 。
固定频率触发定时任务scheduleAtFixedRate() 方法,可以固定多久就触发一次任务 。下面我们写一个延迟 2 秒后开始执行任务,经过 5 秒后再执行下一次的任务的代码:
@Slf4jpublic class ScheduledExecutorServiceDemo {public static void main(String[] args) throws ExecutionException, InterruptedException {testFixedRate();}public static void testFixedRate() {ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();log.info("2秒后开始执行任务,此刻时间---{}", LocalDateTime.now());// 固定频率(每隔5秒)开始执行一个任务scheduledExecutorService.scheduleAtFixedRate(() -> {log.info("任务开始---{}", LocalDateTime.now());try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}log.info("任务结束---{}", LocalDateTime.now());}, 2000, 5000, TimeUnit.MILLISECONDS);}}

经验总结扩展阅读