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

前言学过定时任务,但是我忘了 , 忘得一干二净,害怕 , 一直听别人说:

你写一个定时任务就好了 。
写个定时任务让他去爬取就行了 。
我不会,所以现在得补回来了,欠下的终究要还的,/(ㄒoㄒ)/~~
定时任务是什么?大家都用过闹钟,闹钟可以说是一种定时任务 。
比如我们设定了周一到周五早上7点半的时间响铃,那么闹钟就会在周一到周五的早上7点半进行响铃 , 这种就是定时的任务 。时间定在 周一到周五的早上7点半,任务就是 响铃 。
那么 , 在 Java 中,如何实现这样的功能呢?即如何实现定时任务呢?
定时任务的有哪些是实现方式?
说明:@Slf4j 注解来源于 Lombok,需要引入 Lombok 依赖
纯手写单线程循环单线程,写一个死循环,通过线程的睡眠(等待)完成定时任务:
@Slf4jpublic class ThreadTaskDemo {public static void main(String[] args) {timer1();}public static void timer1() {new Thread(() -> {while (true) {log.info("当前时间 {}", LocalDateTime.now());try {// 每个1秒执行一次Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}}}).start();}}控制台输出:
14:02:35.893 [Thread-0] INFO cn.god23bin.demo.timer.ThreadTaskDemo - 当前时间 2022-10-25T14:02:35.89214:02:36.904 [Thread-0] INFO cn.god23bin.demo.timer.ThreadTaskDemo - 当前时间 2022-10-25T14:02:36.90414:02:37.907 [Thread-0] INFO cn.god23bin.demo.timer.ThreadTaskDemo - 当前时间 2022-10-25T14:02:37.907可以看到每秒执行一次,成功实现了定时任务 。
Timer 和它的小伙伴在 java.util 包下,有这么 3 个东西,分别是 Timer 类、TimerTask 接口、TimerThread 类,这 3 个东西就可以帮我们实现定时任务 。
Timer 有这么 2 个方法(当然不止这两个 , 还有 4 个相关的):
// 延迟delay秒后执行task任务public void schedule(TimerTask task, long delay);// 延迟delay秒后,以period间隔时间执行task任务public void schedule(TimerTask task, long delay, long period);TimerTask 有个 run() 抽象方法 , 那我们可以实现这个抽象方法作为我们的任务逻辑,由于 TimerTask 是接口,需要一个类实现它,那我们下面就用匿名内部类的方式来实现这个接口 。代码如下:
@Slf4jpublic class TimerDemo {public static void main(String[] args) {timer1();}public static void timer1() {// 单线程Timer timer = new Timer();log.info("1秒后执行任务A,A完成后,等待1秒开始定时执行任务B,当前时间 {}", LocalDateTime.now());// 1秒后执行timer.schedule(new TimerTask() {@Overridepublic void run() {log.info("任务A 当前时间 {}", LocalDateTime.now());}}, 1000); // 这里 1000,就是代表延迟 1000 毫秒后再执行// 每隔2秒执行一次这个任务timer.schedule(new TimerTask() {@Overridepublic void run() {log.info("定时任务B 当前时间 {}", LocalDateTime.now());}}, 1000, 2000); // 1000 同理,2000 即执行完本次任务后 , 隔 2000 毫秒后再一次执行 , 达到定时任务的效果}}控制台输出:
14:09:37.416 [main] INFO cn.god23bin.demo.timer.TimerDemo - 1秒后执行任务A , A完成后,等待1秒开始定时执行任务B,当前时间 2022-10-25T14:09:37.41514:09:38.428 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 任务A 当前时间 2022-10-25T14:09:38.42814:09:38.428 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 定时任务B 当前时间 2022-10-25T14:09:38.42814:09:40.443 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 定时任务B 当前时间 2022-10-25T14:09:40.44314:09:42.457 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 定时任务B 当前时间 2022-10-25T14:09:42.457从控制台输出的时间可以看到,任务 A 是只执行了一次,因为我们没有传递 period 参数给 schedule () 方法 。而任务 B 是一个定时任务 , 因为传递了 period 参数,period 参数为 2000,即 2000 毫秒 。
所以 , 任务 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);

推荐阅读