定時任務應該這麼玩

1.場景

在電商系統中會常常遇到這樣一種場景,就是商品的定時上下架功能,總不能每次都手動執行吧,這個時候咱們首先想到的就是利用定時任務來實現這個功能。html

目前實現定時任務主要有如下幾種方式:java

  • JDK自帶 :JDK自帶的Timer以及JDK1.5+ 新增的ScheduledExecutorService;web

  • 第三方框架 :使用 Quartz、elastic-job、xxl-job 等開源第三方定時任務框架,適合分佈式項目應用。該方式的缺點是配置複雜。spring

  • Spring :使用 Spring 提供的一個註解 @Schedule,開發簡單,使用比較方便。apache

本文博主主要向你們介紹Quartz框架和Spring定時任務的使用。json

2.什麼是Quartz

Quartz 是一個徹底由 Java 編寫的開源做業調度框架,爲在 Java 應用程序中進行做業調度提供了簡單卻強大的機制。框架

Quartz 能夠與 J2EE 與 J2SE 應用程序相結合也能夠單獨使用。maven

Quartz 容許程序開發人員根據時間的間隔來調度做業。分佈式

Quartz 實現了做業和觸發器的多對多的關係,還能把多個做業與不一樣的觸發器關聯。ide

3.Quartz幾個核心概念

在正式學習使用Quartz以前,咱們須要瞭解幾個有關Quartz的核心概念,方便咱們後面學習

  1. Job 表示一個工做,要執行的具體內容。此接口中只有一個方法,以下:

    void execute(JobExecutionContext context) 
    // context是重要的上下文,能夠訪問到關聯的JobDetail對象和本次觸發的Trigger對象,以及在此之上設定的數據。
  2. JobDetail 表示一個具體的可執行的調度程序,Job 是這個可執行程調度程序所要執行的內容,另外 JobDetail 還包含了這個任務調度的方案和策略。

  3. Trigger 表明一個調度參數的配置,何時去調。

  4. Scheduler 表明一個調度容器,一個調度容器中能夠註冊多個 JobDetail 和 Trigger。當 Trigger 與 JobDetail 組合,就能夠被 Scheduler 容器調度了。

4.Quartz初體驗

1、建立一個SpringBoot項目,pom.xml配置以下

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.songguoliang</groupId>
    <artifactId>spring-boot-quartz</artifactId>
    <version>1.0-SNAPSHOT</version>

    <name>spring-boot-quartz</name>
    <description>Spring Boot使用Quartz定時任務</description>

    <!-- Spring Boot啓動器父類 -->
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.1.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <!-- Spring Boot web啓動器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- quartz -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2、建立一個Job(Job裏面是要執行的具體內容)

package com.example.quartz;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;

import java.time.LocalDateTime;

public class TestJob implements Job {

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 經過context獲取trigger中的數據
        Object tv1 = context.getTrigger().getJobDataMap().get("t1");
        Object tv2 = context.getTrigger().getJobDataMap().get("t2");
        // 經過context獲取JobDetail中的數據
        Object jv1 = context.getJobDetail().getJobDataMap().get("j1");
        Object jv2 = context.getJobDetail().getJobDataMap().get("j2");
        Object sv = null;
        try {
            sv = context.getScheduler().getContext().get("skey");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        System.out.println(tv1+":"+tv2);
        System.out.println(jv1+":"+jv2);
        System.out.println(sv);
        System.out.println("date:"+ LocalDateTime.now());
    }
}

3、執行Job

package com.example.quartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzTest {
    public static void main(String[] args)  {
        try {
            //建立一個scheduler
            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
            //向scheduler中put值
            scheduler.getContext().put("skey", "svalue");

            //建立一個Trigger
            Trigger trigger = TriggerBuilder.newTrigger()
                    //給該Trigger起一個id
                    .withIdentity("trigger1")
                    //以Key-Value形式關聯數據
                    .usingJobData("t1", "tv1")
                    //每3秒觸發一次,無限循環
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
                            .repeatForever()).build();
            trigger.getJobDataMap().put("t2","tv2");

            //建立一個JobDetail
            JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
                    //給該JobDetail起一個id
                    .withIdentity("myJob", "myGroup")
                    .usingJobData("j1", "jv1")
                    .build();
            jobDetail.getJobDataMap().put("j2", "jv2");

            //註冊trigger並啓動scheduler
            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();
            //若是想要中止這個Job,能夠調用shutdown方法
            //scheduler.shutdown();

        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}

控制檯輸出

10:46:54.075 [main] INFO org.quartz.impl.StdSchedulerFactory - Using default implementation for ThreadExecutor
10:46:54.079 [main] INFO org.quartz.simpl.SimpleThreadPool - Job execution threads will use class loader of thread: main
10:46:54.089 [main] INFO org.quartz.core.SchedulerSignalerImpl - Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl
10:46:54.089 [main] INFO org.quartz.core.QuartzScheduler - Quartz Scheduler v.2.3.2 created.
10:46:54.090 [main] INFO org.quartz.simpl.RAMJobStore - RAMJobStore initialized.
10:46:54.091 [main] INFO org.quartz.core.QuartzScheduler - Scheduler meta-data: Quartz Scheduler (v2.3.2) 'DefaultQuartzScheduler' with instanceId 'NON_CLUSTERED'
  Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally.
  NOT STARTED.
  Currently in standby mode.
  Number of jobs executed: 0
  Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads.
  Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered.

10:46:54.091 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler 'DefaultQuartzScheduler' initialized from default resource file in Quartz package: 'quartz.properties'
10:46:54.091 [main] INFO org.quartz.impl.StdSchedulerFactory - Quartz scheduler version: 2.3.2
10:46:54.104 [main] INFO org.quartz.core.QuartzScheduler - Scheduler DefaultQuartzScheduler_$_NON_CLUSTERED started.
10:46:54.104 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
10:46:54.106 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.example.quartz.TestJob
10:46:54.110 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
10:46:54.110 [DefaultQuartzScheduler_Worker-1] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
tv1:tv2
jv1:jv2
svalue
date:2020-12-19T10:46:54.144
10:46:57.092 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.example.quartz.TestJob
10:46:57.092 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
10:46:57.092 [DefaultQuartzScheduler_Worker-2] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
tv1:tv2
jv1:jv2
svalue
date:2020-12-19T10:46:57.092
10:47:00.101 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.example.quartz.TestJob
10:47:00.101 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
10:47:00.101 [DefaultQuartzScheduler_Worker-3] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
tv1:tv2
jv1:jv2
svalue
date:2020-12-19T10:47:00.101
10:47:03.096 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.simpl.PropertySettingJobFactory - Producing instance of Job 'myGroup.myJob', class=com.example.quartz.TestJob
10:47:03.096 [DefaultQuartzScheduler_QuartzSchedulerThread] DEBUG org.quartz.core.QuartzSchedulerThread - batch acquisition of 1 triggers
10:47:03.096 [DefaultQuartzScheduler_Worker-4] DEBUG org.quartz.core.JobRunShell - Calling execute on job myGroup.myJob
tv1:tv2
jv1:jv2
svalue
date:2020-12-19T10:47:03.096

從輸出結果咱們能夠看到此Job每隔3秒執行一次

有關概念

一、Job

job的一個 trigger 被觸發後(稍後會講到),execute() 方法會被 scheduler 的一個工做線程調用;傳遞給 execute() 方法的 JobExecutionContext 對象中保存着該 job 運行時的一些信息 ,執行 job 的 scheduler 的引用,觸發 job 的 trigger 的引用,JobDetail 對象引用,以及一些其它信息。

二、JobDetail

JobDetail 對象是在將 job 加入 scheduler 時,由客戶端程序(你的程序)建立的。它包含 job 的各類屬性設置,以及用於存儲 job 實例狀態信息的 JobDataMap

三、Trigger

Trigger 用於觸發 Job 的執行。當你準備調度一個 job 時,你建立一個 Trigger 的實例,而後設置調度相關的屬性。Trigger 也有一個相關聯的 JobDataMap,用於給 Job 傳遞一些觸發相關的參數。Quartz 自帶了各類不一樣類型的 Trigger,最經常使用的主要是 SimpleTrigger 和 CronTrigger。SimpleTrigger 主要用於一次性執行的 Job(只在某個特定的時間點執行一次),或者 Job 在特定的時間點執行,重複執行 N 次,每次執行間隔T個時間單位。CronTrigger 在基於日曆的調度上很是有用,如「每一個星期五的正午」,或者「每個月的第十天的上午 10:15」等。

5.JobDetail詳解

在定義一個Job時,咱們須要實現Job接口,該接口只有一個execute方法。

從上一節的案例中咱們能夠發現,咱們經過Scheduler去執行Job,咱們傳給scheduler一個JobDetail實例,由於咱們在建立JobDetail時,將要執行的job的類名傳給了JobDetail,因此scheduler就知道了要執行何種類型的job。(這裏利用了Java中的反射建立實例對象)每次當scheduler執行job時,在調用其execute(…)方法以前會建立該類的一個新的實例;執行完畢,對該實例的引用就被丟棄了,實例會被垃圾回收;這種執行策略帶來的一個後果是,job必須有一個無參的構造函數(當使用默認的JobFactory時);另外一個後果是,在job類中,不該該定義有狀態的數據屬性,由於在job的屢次執行中,這些屬性的值不會保留。

那麼咱們該如何給Job配置相關屬性呢?答案就是經過JobDetail

JobDataMap

JobDataMap實現了Map接口,能夠存放鍵值對數據,在Job執行的時候,咱們就能夠經過JobExecutionContext獲取到JobDataMap中的數據,以下

JobDetail jobDetail = JobBuilder.newJob(TestJob.class)
                    .withIdentity("myJob", "myGroup")
                    .usingJobData("j1", "jv1")
                    .usingJobData("j2","jv2")
                    .build();

在job的執行過程當中,能夠從JobDataMap中取出數據,以下示例:

Object jv1 = context.getJobDetail().getJobDataMap().get("j1");

固然,若是你但願實現屬性的自動注入,那麼你可使用下面的方法

package com.example.quartz;

import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;

public class QuartzTest2 {
    public static void main(String[] args)  {
        try {

            Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();

            Trigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("trigger1")
                    .usingJobData("t1", "tv1")
                    .withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3)
                            .repeatForever())
                    .build();

            JobDetail jobDetail = JobBuilder.newJob(TestJob2.class)
                    .withIdentity("jd")
                    .usingJobData("name", "張三")
                    .usingJobData("age", 12)
                    .build();

            scheduler.scheduleJob(jobDetail, trigger);
            scheduler.start();

        } catch (SchedulerException e) {
            e.printStackTrace();
        }
    }
}
package com.example.quartz;

import org.quartz.*;

public class TestJob2 implements Job {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        JobKey jobKey = context.getJobDetail().getKey();

        JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();

        System.out.println("name:" + name + "age:" +age);
    }
}

給Job類加上get和set方法(屬性名稱要和JobDataMap中的key相同),那麼JobDataMap中的值就是自動注入到Job中,不須要手動獲取

6.Triggers詳解

Trigger 用於觸發 Job 的執行。當你準備調度一個 job 時,你建立一個 Trigger 的實例,而後設置調度相關的屬性。全部類型的trigger都有TriggerKey這個屬性,表示trigger的身份;除此以外,trigger還有不少其它的公共屬性。這些屬性,在構建trigger的時候能夠經過TriggerBuilder設置。

triggers公共屬性

  • jobKey屬性:當trigger觸發時被執行的job的身份;
  • startTime屬性:設置trigger第一次觸發的時間;該屬性的值是java.util.Date類型,表示某個指定的時間點;有些類型的trigger,會在設置的startTime時當即觸發,有些類型的trigger,表示其觸發是在startTime以後開始生效。好比,如今是1月份,你設置了一個trigger–「在每月的第5天執行」,而後你將startTime屬性設置爲4月1號,則該trigger第一次觸發會是在幾個月之後了(即4月5號)。
  • endTime屬性:表示trigger失效的時間點。好比,」每個月第5天執行」的trigger,若是其endTime是7月1號,則其最後一次執行時間是6月5號。

優先級(priority)

若是你的trigger不少(或者Quartz線程池的工做線程太少),Quartz可能沒有足夠的資源同時觸發全部的trigger;這種狀況下,你可能但願控制哪些trigger優先使用Quartz的工做線程,要達到該目的,能夠在trigger上設置priority屬性。好比,你有N個trigger須要同時觸發,但只有Z個工做線程,優先級最高的Z個trigger會被首先觸發。若是沒有爲trigger設置優先級,trigger使用默認優先級,值爲5;priority屬性的值能夠是任意整數,正數、負數均可以。

注意:只有同時觸發的trigger之間纔會比較優先級。10:59觸發的trigger老是在11:00觸發的trigger以前執行。

注意:若是trigger是可恢復的,在恢復後再調度時,優先級與原trigger是同樣的。

錯過觸發(misfire Instructions)

trigger還有一個重要的屬性misfire;若是scheduler關閉了,或者Quartz線程池中沒有可用的線程來執行job,此時持久性的trigger就會錯過(miss)其觸發時間,即錯過觸發(misfire)。不一樣類型的trigger,有不一樣的misfire機制。它們默認都使用「智能機制(smart policy)」,即根據trigger的類型和配置動態調整行爲

Simple Trigger

SimpleTrigger簡單點說,就是在具體的時間點執行一次,或者在具體的時間點執行,而且以指定的間隔重複執行若干次。相似於鬧鐘,你定了一個週末早晨7點的鬧鐘,這個鬧鐘會在週末早上7點準時響起。鬧鐘還有個功能就是過5分鐘以後再響一次,這對應着指定的間隔重複執行若干次。

一、指定時間開始觸發,不重複:

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
                    .withIdentity("st1", "group1")
                    .startAt(new Date()) // 從當前時間開始執行一次,不重複
                    .build();

二、指定時間觸發,每隔2秒執行一次,重複5次:

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("st2", "group1")
        .startAt(new Date())
        .withSchedule(SimpleScheduleBuilder.simpleSchedule()
                .withIntervalInSeconds(2) // 2秒
                .withRepeatCount(5)// 5次
        )
        .build();

三、1分鐘之後開始觸發,僅執行一次:

long time = 1 * 60 * 1000;
Date now = new Date();
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("st3", "group1")
        .startAt(new Date(now.getTime() + time))
        .build();

四、當即觸發,每隔2秒鐘執行一次,直到2020-12-19 13:20:00

String dateStr="2020-12-19 13:20:00";
String pattern="yyyy-MM-dd HH:mm:ss";
SimpleDateFormat dateFormat=new SimpleDateFormat(pattern);
Date date = dateFormat.parse(dateStr);
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("st4", "group1")
        .withSchedule(SimpleScheduleBuilder.simpleSchedule()
        .withIntervalInSeconds(2)
        .repeatForever())
        .endAt(date)
        .build();

五、在13:00觸發,而後每2小時重複一次:

String dateStr="2020-12-19 13:00:00";
String pattern="yyyy-MM-dd HH:mm:ss";
SimpleDateFormat dateFormat=new SimpleDateFormat(pattern);
Date date = dateFormat.parse(dateStr);
SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("st2", "group1")
        .withSchedule(SimpleScheduleBuilder.simpleSchedule()
        .withIntervalInHours(2)
        .repeatForever())
        .build();

SimpleTrigger Misfire

misfire:被錯過的執行任務策略

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withIdentity("st6")
        .withSchedule(
                SimpleScheduleBuilder.simpleSchedule()
                        .withIntervalInMinutes(5)
                        .repeatForever()
                        .withMisfireHandlingInstructionNextWithExistingCount()
        )
        .build();

CronTrigger

CronTrigger一般比Simple Trigger更有用,若是你須要在指定日期執行某項任務,使用CronTrigger就很是方便,好比若是你想在每個月的15號給會員發放優惠券,或者每週五中午12點統計用戶本週使用產品時長。

cron 表達式是一個字符串,該字符串由 6 個空格分爲 7 個域,每個域表明一個時間含義。 一般定義 「年」 的部分能夠省略,實際經常使用的 Cron 表達式由前 6 部分組成。格式以下

[秒] [分] [時] [日] [月] [周] [年]
 Seconds  Minutes  Hours   Day-of-Month  Month   Day-of-Week	Year (optional field)
是否必填 值以及範圍 通配符
0-59 , - * /
0-59 , - * /
0-23 , - * /
1-31 , - * ? / L W
1-12 或 JAN-DEC , - * /
1-7 或 SUN-SAT , - * ? / L #
1970-2099 , - * /

須要說明的是,Cron 表達式中,「周」 是從週日開始計算的。「周」 域上的 1 表示的是週日,7 表示週六。

天天晚上12點觸發任務:0 0 0 * * ?

每隔 1 分鐘執行一次:0 */1 * * * ?

每個月 1 號凌晨 1 點執行一次:0 0 1 1 * ?

每個月最後一天 23 點執行一次:0 0 23 L * ?

每週週六凌晨 3 點實行一次:0 0 3 ? * L

在24分,30分執行一次:0 24,30 * * * ?

是否是有點沒看懂,不要緊,咱們可使用Cron表達式生成器幫助咱們生成Cron表達式

SimpleTrigger trigger = (SimpleTrigger) TriggerBuilder.newTrigger()
        .withSchedule(CronScheduleBuilder.cronSchedule("0 0/2 8-17 * * ?"))
        .build();

7.@Schedule實現定時任務

不少時候咱們都須要爲系統創建一個定時任務來幫咱們作一些事情,SpringBoot 已經幫咱們實現好了一個,咱們只須要直接使用便可

1、引入依賴

<dependencies>

 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
 </dependency>

 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter</artifactId>
 </dependency>

 <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
 </dependency>

 <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
 </dependency>

</dependencies>

2、開啓註解

在 SpringBoot 中咱們只須要在啓動類上加上@EnableScheduling即可以啓動定時任務了。

@SpringBootApplication
@EnableScheduling
public class TaskApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

3、建立scheduled task

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * @author wugongzi
 */
@Component
public class ScheduledTasks {
    private static final Logger log = LoggerFactory.getLogger(ScheduledTasks.class);
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    /**
     * fixedRate:固定速率執行。每5秒執行一次。
     */
    @Scheduled(fixedRate = 5000)
    public void reportCurrentTimeWithFixedRate() {
        log.info("Current Thread : {}", Thread.currentThread().getName());
        log.info("Fixed Rate Task : The time is now {}", dateFormat.format(new Date()));
    }

    /**
     * fixedDelay:固定延遲執行。距離上一次調用成功後2秒才執。
     */
    @Scheduled(fixedDelay = 2000)
    public void reportCurrentTimeWithFixedDelay() {
        try {
            TimeUnit.SECONDS.sleep(3);
            log.info("Fixed Delay Task : The time is now {}", dateFormat.format(new Date()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * initialDelay:初始延遲。任務的第一次執行將延遲5秒,而後將以5秒的固定間隔執行。
     */
    @Scheduled(initialDelay = 5000, fixedRate = 5000)
    public void reportCurrentTimeWithInitialDelay() {
        log.info("Fixed Rate Task with Initial Delay : The time is now {}", dateFormat.format(new Date()));
    }

    /**
     * cron:使用Cron表達式。 每分鐘的1,2秒運行
     */
    @Scheduled(cron = "1-2 * * * * ? ")
    public void reportCurrentTimeWithCronExpression() {
        log.info("Cron Expression: The time is now {}", dateFormat.format(new Date()));
    }
}

啓動項目即可以看到效果。

相關文章
相關標籤/搜索