一文搞定Spring Task

2023-01-08 06:00:52

今天和大家分享下Spring Task這個知識點,主要通過下面6個點來展開描述,希望能夠幫助到大家。

1、什麼是定時任務

2、入門案例

3、Corn表示式

4、Corn實戰案例

5、@Scheduled

6、多執行緒任務

1、什麼是定時任務

定時任務是系統在特定時間執行一段程式碼。

定時任務的實現主要有以下幾種方式:

  • Java自帶的java.util.Timer類。它允許排程一個java.util.TimerTask任務,使用這種方式可以讓程式按照某一個頻度執行,但不能在指定時間執行,一般運用較少。
  • Quartz。是一個功能比較強大的排程器,可以讓程式在執行時間執行,也可以按照某個頻度執行,設定起來有點複雜。
  • Spring3.0以後自帶Spring Task。可以看成一個輕量級的Quartz,

2、入門案例

1、建立SpringBoot專案在啟動類開啟定時任務@EnableScheduling

@SpringBootApplication
@EnableScheduling
public class SpringtaskdemoApplication {

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

}
//每秒都執行一次
@Scheduled(cron = "* * * * * *")
    public void test(){
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        System.out.println(format.format(new Date()));
    }

3、Corn表示式

Spring Task 依靠Corn表示式設定定時規則,Corn表示式是一個字串,分為6或7個域。每個域代表一個含義,以空格隔開,有如下兩種語法格式:

1、秒 分 時 每月第幾天 月份 周幾 年份

2、秒 分 時 每月第幾天 月份 周幾

3.1 秒

Seconds(秒)域可以出現,- * /0-59的整數

  • *:表示匹配該域的任意值,在Seconds域中使用 * 表示每秒鐘都會出發

  • ,:表示列出列舉值,在Seconds域中使用5,20表示在5秒和20秒各觸發一次

  • -:表示範圍,在secondes域使用5-20,表示從5秒到20秒每秒觸發一次

  • /:表示起始時間開始觸發,然後每隔固定時間觸發一次,在secondes域中使用5/20,表示第5秒觸發一次,25秒、45秒各觸發一次。

3.2 分、時

以上四個字元在minutes和Hours域都可以出現。分鐘整數為0-59,小時整數為0-23

3.3 日期

DayofMonty(日期):域中可以出現,- * / ? L W C 八個字元,以及1-31的整數。

  • c:表示和當前日期相關聯,如果在該域使用5c ,則在執行當天的5日後執行,且每月的那天都會執行。比如執行日是10號,則每月的15號都會觸發。
  • L:表示最後,在該域使用L,表示每月的最後一天觸發;
  • W:表示工作日,在該域用15W,表示在最接近本月第15天的工作日出發,如果15號是週六則14號觸發,如果15號是週日則16號出發,如果15號是週二,則15號觸發。 注:該用法只會在當前月計算,不會到下月觸發,比如在DayofMonth域用31W,31號是週日,那麼在29號觸發,而不是下月1號。
  • 在DayofMonth域用LW,表示這個月的最後一個工作日觸發。

3.4 月份

Month(月份):域中可出現,- * / 四個字元,以及1-12的整數或JAN-DEC的單詞縮寫

3.5 星期

DayofWeek(星期):可出現,- * / ? L # C 八個字元,以及1-7的整數或SUN-SAT單詞的縮寫,1代表星期天,7代表週六

  • c:在DayofWeek域使用2c,表示在啟動日後的2天后觸發,且每週的那天都會觸發,如在週一啟動,那麼每週三都會觸發;
  • L:L表示一週的最後一天(週六)觸發,如果使用5L,表示在一個月的最後一個週四觸發
  • :用來執行具體的週數,#前面代表星期幾,#後面代表一個月的第幾周。如5#3表示一個月第三週的星期四

  • ?:在無法確定是哪一天時使用。用於DayofMonth和DayofWeek域。如每個21號零點觸發1次,此時無法確定21號是周幾,就寫 0 0 0 21 * ?

3.6 年份

Year(年份):,- * / 四個字元,以及 1970~2099的整肅,該域可以省略,表示每年都會觸發。

4、Corn實戰案例

每間隔5分鐘觸發一次 :0 0/5 * * * *
     每小時觸發一次 0 0 * * * *
     每天7:30觸發 0 30 7 * * *
     每週一到週五早上6:30觸發  0 30 6 ? * 2-6
     每月最後一天早上10點觸發 0 0 10 L * ?
     每月最後一個工作日的18:30分觸發 0 30 18 LW * ?
     2030年8月每個星期六和星期日早上10觸發 0 0 10 ? 8 7,1 2030
     每天10點、12點、14點觸發 0 0 10,12,14 * * *
     朝九晚五工作日內每半小時觸發一次 0 0/30 9-17 W * ?
     
     每週三中午12點觸發一次 0 0 12 ? * 4
     每天12點觸發一次 0 0  12 * * *
     每天14點到14:59每分鐘觸發一次 0 *  14 * * *
     每天14點到14:59每5分鐘觸發一次 0 0/5 14 * * *
     每天14點到14:05每分鐘觸發一次 0 0-5 14 * * *
     每月15日上午10:15觸發  0 15 10 15 * ?
     每月最後一天的上午10:15觸發 0 15 10 L * ?
     每月的第三個星期五上午10;15觸發 0 15 10 ? * 6#3

5、Spring Tash @Scheduled

@Scheduled指定方法定時執行

@Scheduled寫在方法上方,指定該方法定時執行,常用引數如下:

  • cron :cron制定方法執行的時間規則
  • fixedDelay :任務立即執行,之後每隔多久就執行一次,單位是毫秒,上次任務結束後計算下次執行的時間
//立即執行,任務結束後每5秒執行一次
    @Scheduled(fixedDelay = 5000)
    public void task2() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));

    }
  • fixedRate:任務立即執行,之後每隔多久就執行一次,單位毫秒,上次任務開始後開始計時
//立即執行,任務開始後每5秒執行一次
@Scheduled(fixedRate = 5000)
    public void task3() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));

    }
  • initialDelay:專案啟動後不馬上執行定時器,根據initialDelay 延時執行
//專案啟動3s後,之後每5s執行一次
    @Scheduled(fixedRate = 5000,initialDelay = 3000)
    public void task4() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(1000);
        System.out.println(format.format(new Date()));
    }

6、Spring Task 多執行緒任務

Spring Task定時器預設是單執行緒的,如果專案中使用多個定時器,使用一個執行緒會造成效率低下如:

@Scheduled(cron = "* * * * * *")
    public void task5() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(5000);
        System.out.println(format.format(new Date())+Thread.currentThread().getId()+"執行緒任務1");
    }
    @Scheduled(cron = "* * * * * *")
    public void task6() throws InterruptedException {
        SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
        Thread.sleep(5000);
        System.out.println(format.format(new Date())+Thread.currentThread().getId()+"執行緒任務2");
    }

解決這個問題我們可以建立一個執行緒池。

@Configuration
public class SchedulingConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        //建立執行緒池
        taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
    }
}

歡迎轉載,轉載請註明原文出處
個人公眾號 :hellotqq,歡迎關注交流與您共同成長!