5

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

 2 years ago
source link: https://www.cnblogs.com/god23bin/p/I-can-finally-write-scheduled-tasks-in-Java.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

你写一个定时任务就好了。

写个定时任务让他去爬取就行了。

我不会,所以现在得补回来了,欠下的终究要还的,/(ㄒoㄒ)/~~

定时任务是什么?

大家都用过闹钟,闹钟可以说是一种定时任务。

比如我们设定了周一到周五早上7点半的时间响铃,那么闹钟就会在周一到周五的早上7点半进行响铃,这种就是定时的任务。时间定在 周一到周五的早上7点半 ,任务就是 响铃

那么,在 Java 中,如何实现这样的功能呢?即如何实现定时任务呢?

定时任务的有哪些是实现方式?

说明:@Slf4j 注解来源于 Lombok ,需要引入 Lombok 依赖

纯手写单线程循环

单线程,写一个死循环,通过线程的睡眠(等待)完成定时任务:

@Slf4j
public 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.892
14:02:36.904 [Thread-0] INFO cn.god23bin.demo.timer.ThreadTaskDemo - 当前时间 2022-10-25T14:02:36.904
14: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 是接口,需要一个类实现它,那我们下面就用匿名内部类的方式来实现这个接口。代码如下:

@Slf4j
public 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() {
            @Override
            public void run() {
                log.info("任务A 当前时间 {}", LocalDateTime.now());
            }
        }, 1000); // 这里 1000,就是代表延迟 1000 毫秒后再执行

        // 每隔2秒执行一次这个任务
        timer.schedule(new TimerTask() {
            @Override
            public 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.415
14:09:38.428 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 任务A 当前时间 2022-10-25T14:09:38.428
14:09:38.428 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 定时任务B 当前时间 2022-10-25T14:09:38.428
14:09:40.443 [Timer-0] INFO cn.god23bin.demo.timer.TimerDemo - 定时任务B 当前时间 2022-10-25T14:09:40.443
14: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 接口。

ScheduledExecutorService

ScheduledExecutorService 接口位于 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() 方法实现定时任务。

现在先看一下,如何使用:

@Slf4j
public 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.509
14:15:46.524 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:15:46.524
14:15:48.537 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:15:48.537
14:15:48.538 [main] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务执行后 future ok, 时间 2022-10-25T14:15:48.538

很明显,这里不是一个定时任务,因为只执行了一次就结束了,所以我们需要调用两外两个来实现,分别是 scheduleAtFixedRate() 方法和 scheduleWithFixedDelay() 方法。

固定频率触发定时任务

scheduleAtFixedRate() 方法,可以固定多久就触发一次任务。下面我们写一个延迟 2 秒后开始执行任务,经过 5 秒后再执行下一次的任务的代码:

@Slf4j
public 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);
    }
}

通过 Thread.sleep(2000) 模拟任务执行了 2 秒的时间,控制台输出如下:

14:17:15.081 [main] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 2秒后开始执行任务,此刻时间---2022-10-25T14:17:15.079
14:17:17.094 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:17:17.094
14:17:19.109 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:17:19.109
14:17:22.094 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:17:22.094
14:17:24.106 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:17:24.106
14:17:27.090 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:17:27.090
14:17:29.099 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:17:29.099

可以看到,第一次执行的时间是 14:17:17 ,即第 17 秒,下一次执行的时间是 14:17:22 ,即第 22 秒,这个过程经过了 5 秒钟,这就是 scheduleAtFixedRate() 方法的效果。

固定延迟触发定时任务

scheduleWithFixedDelay() 方法,可以固定任务完成后延迟多久才执行下一次任务。下面我们写一个延迟 1 秒后开始执行定时任务,当任务完成后,延迟 4 秒再执行下一次任务。代码如下:

@Slf4j
public 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.351
14:20:32.370 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:20:32.370
14:20:34.371 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务结束---2022-10-25T14:20:34.371
14:20:38.379 [pool-1-thread-1] INFO cn.god23bin.demo.timer.ScheduledExecutorServiceDemo - 任务开始---2022-10-25T14:20:38.379
14: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
@EnableScheduling
public 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.013  INFO 18304 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 此刻时间 2022-10-25T14:26:22.013
2022-10-25 14:26:23.010  INFO 18304 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 此刻时间 2022-10-25T14:26:23.010
2022-10-25 14:26:24.011  INFO 18304 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 此刻时间 2022-10-25T14:26:24.011
2022-10-25 14:26:25.011  INFO 18304 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 此刻时间 2022-10-25T14:26:25.011

可以看到,确实是每隔 1 秒执行一次 printTime() 这个定时任务。

@Scheduled 的另外两个属性

@Scheduled 注解除了 cron 这个属性外,还有 fixedRate 属性和 fixedDelay 属性,同理,就是固定频率触发定时任务固定延迟触发定时任务

fixedRate
@Slf4j
@Component
@EnableScheduling
public class TaskDemo {

    /**
     * 当前任务执行到下一个任务开始的时间(固定频率开始执行一个任务,每5秒执行),都是单线程处理的
     **/
    @Scheduled(fixedRate = 5000)
    public void printTime1() throws InterruptedException {
        log.info("任务开始------- {}", LocalDateTime.now());
        Thread.sleep(1000);
        log.info("任务完成------- {}", LocalDateTime.now());
    }
    
}

控制台输出:

2022-10-25 14:54:04.824  INFO 23520 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:54:04.824
2022-10-25 14:54:05.833  INFO 23520 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:54:05.833
2022-10-25 14:54:09.834  INFO 23520 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:54:09.834
2022-10-25 14:54:10.843  INFO 23520 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:54:10.843

当然,如果任务的处理逻辑超过了固定的频率时间,比如我们修改下 Thread.sleep(1000) ,模拟成 6 秒,即 Thread.sleep(6000),那么输出如下:

2022-10-25 14:57:04.212  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:57:04.212
2022-10-25 14:57:10.227  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:57:10.227
2022-10-25 14:57:10.227  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:57:10.227
2022-10-25 14:57:16.241  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:57:16.241
2022-10-25 14:57:16.242  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:57:16.242
2022-10-25 14:57:22.243  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:57:22.243
2022-10-25 14:57:22.243  INFO 9324 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:57:22.243

可以发现,当前任务一完成就会立刻执行下一次任务,这就是当任务的处理逻辑超过了固定的频率时间会出现的情况。

fixedDelay
@Slf4j
@Component
@EnableScheduling
public class TaskDemo {

    /**
     * 执行完成后间隔2秒执行下一次
     **/
    @Scheduled(fixedDelay = 2000)
    public void printTime2() throws InterruptedException {
        log.info("任务开始------- {}", LocalDateTime.now());
        Thread.sleep(4000);
        log.info("任务完成------- {}", LocalDateTime.now());
    }
    
}

控制台输出:

2022-10-25 14:55:50.973  INFO 22128 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:55:50.973
2022-10-25 14:55:54.977  INFO 22128 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:55:54.977
2022-10-25 14:55:56.987  INFO 22128 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:55:56.987
2022-10-25 14:56:01.001  INFO 22128 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务完成------- 2022-10-25T14:56:01.001
2022-10-25 14:56:03.012  INFO 22128 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务开始------- 2022-10-25T14:56:03.012

多个定时任务的执行

如果我们写多个定时任务,那么它们只会同步执行,如下:

@Slf4j
@Component
@EnableScheduling
public class TaskDemo {

    @Scheduled(fixedRate = 2000)
    public void printTime3() throws InterruptedException {
        log.info("任务A开始------- {}", LocalDateTime.now());
        Thread.sleep(2000);
        log.info("任务A完成------- {}", LocalDateTime.now());
    }

    @Scheduled(fixedDelay = 2000)
    public void printTime4() throws InterruptedException {
        log.info("任务B开始------- {}", LocalDateTime.now());
        Thread.sleep(2000);
        log.info("任务B完成------- {}", LocalDateTime.now());
    }
    
}

控制台输出:

2022-10-25 14:59:14.279  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T14:59:14.279
2022-10-25 14:59:16.283  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T14:59:16.283
2022-10-25 14:59:16.283  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务B开始------- 2022-10-25T14:59:16.283
2022-10-25 14:59:18.288  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务B完成------- 2022-10-25T14:59:18.288
2022-10-25 14:59:18.288  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T14:59:18.288
2022-10-25 14:59:20.301  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T14:59:20.301
2022-10-25 14:59:20.301  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T14:59:20.301
2022-10-25 14:59:22.307  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T14:59:22.307
2022-10-25 14:59:22.307  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T14:59:22.307
2022-10-25 14:59:24.323  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T14:59:24.323
2022-10-25 14:59:24.323  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务B开始------- 2022-10-25T14:59:24.323
2022-10-25 14:59:26.337  INFO 21588 --- [   scheduling-1] cn.god23bin.demo.task.TaskDemo           : 任务B完成------- 2022-10-25T14:59:26.337

可以看到,只有某一个任务完成后,下一个任务才会执行。

如果想要异步,如何异步呢?

很简单,使用 @EnableAsync@Async 这两个注解就可以了,如下:

@Slf4j
@Component
@EnableScheduling
@EnableAsync
public class TaskDemo {

    @Async
    @Scheduled(fixedRate = 2000)
    public void printTime3() throws InterruptedException {
        log.info("任务A开始------- {}", LocalDateTime.now());
        Thread.sleep(2000);
        log.info("任务A完成------- {}", LocalDateTime.now());
    }

    @Async
    @Scheduled(fixedDelay = 2000)
    public void printTime4() throws InterruptedException {
        log.info("任务B开始------- {}", LocalDateTime.now());
        Thread.sleep(2000);
        log.info("任务B完成------- {}", LocalDateTime.now());
    }
    
}

控制台输出:

2022-10-25 15:04:05.833  INFO 15604 --- [         task-1] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T15:04:05.833
2022-10-25 15:04:05.833  INFO 15604 --- [         task-2] cn.god23bin.demo.task.TaskDemo           : 任务B开始------- 2022-10-25T15:04:05.833
2022-10-25 15:04:07.833  INFO 15604 --- [         task-4] cn.god23bin.demo.task.TaskDemo           : 任务B开始------- 2022-10-25T15:04:07.833
2022-10-25 15:04:07.833  INFO 15604 --- [         task-3] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T15:04:07.833
2022-10-25 15:04:07.848  INFO 15604 --- [         task-2] cn.god23bin.demo.task.TaskDemo           : 任务B完成------- 2022-10-25T15:04:07.848
2022-10-25 15:04:07.848  INFO 15604 --- [         task-1] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T15:04:07.848
2022-10-25 15:04:09.833  INFO 15604 --- [         task-5] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T15:04:09.833
2022-10-25 15:04:09.843  INFO 15604 --- [         task-4] cn.god23bin.demo.task.TaskDemo           : 任务B完成------- 2022-10-25T15:04:09.843
2022-10-25 15:04:09.843  INFO 15604 --- [         task-3] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T15:04:09.843
2022-10-25 15:04:09.844  INFO 15604 --- [         task-6] cn.god23bin.demo.task.TaskDemo           : 任务B开始------- 2022-10-25T15:04:09.843
2022-10-25 15:04:11.830  INFO 15604 --- [         task-7] cn.god23bin.demo.task.TaskDemo           : 任务A开始------- 2022-10-25T15:04:11.830
2022-10-25 15:04:11.845  INFO 15604 --- [         task-6] cn.god23bin.demo.task.TaskDemo           : 任务B完成------- 2022-10-25T15:04:11.845
2022-10-25 15:04:11.845  INFO 15604 --- [         task-5] cn.god23bin.demo.task.TaskDemo           : 任务A完成------- 2022-10-25T15:04:11.845

首先讲了下定时任务是什么?接着讲了有哪些实现方式?对这些方式进行介绍。

主要的定时任务可以通过以下的方式实现:

  1. 纯手写单线程死循环,配合线程的等待机制的方式(不推荐,麻烦,问题多多)
  2. 使用 JDK 提供的 Timer 配合 TimerTask 的方式(不推荐,单线程)
  3. 使用 JDK 提供的多线程的 ScheduledExecutorService 的方式(可代替 Timer,多线程的)
  4. 使用 Spring 提供的定时任务的方式(推荐,更加方便,可异步)

当然,除了这些方式,还可以使用定时任务框架,比如 Quartz、XXL-JOB、Elastic-Job 等等。

最后的最后

由本人水平所限,难免有错误以及不足之处, 屏幕前的靓仔靓女们 如有发现,恳请指出!

最后,谢谢你看到这里,谢谢你认真对待我的努力,希望这篇博客对你有所帮助!

你轻轻地点了个赞,那将在我的心里世界增添一颗明亮而耀眼的星!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK