天天看點

Spring Boot使用Schedule實作定時任務0. 開發環境1. 簡單定時任務2. corn表達式3. 配置定時任務4. 動态修改定時任務5. 并發執行定時任務

Java EE 目錄:https://blog.csdn.net/dkbnull/article/details/87932809

Spring Boot 專欄:https://blog.csdn.net/dkbnull/category_9278145.html

Spring Cloud 專欄:https://blog.csdn.net/dkbnull/category_9287932.html

0. 開發環境

  • IDE:IntelliJ IDEA 2017.1 x64
  • jdk:1.8.0_91
  • Spring Boot:2.1.1.RELEASE

1. 簡單定時任務

對于一些比較簡單的定時任務,比如固定時間間隔執行固定方法,在标準Java方法上注解@Scheduled即可

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

    @Scheduled(cron = "0/10 * * * * ?") //每10秒執行一次
    public void scheduledTaskByCorn() {
        LoggerUtils.info("定時任務開始 ByCorn:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByCorn:" + DateUtils.dateFormat());
    }

    @Scheduled(fixedRate = 10000) //每10秒執行一次
    public void scheduledTaskByFixedRate() {
        LoggerUtils.info("定時任務開始 ByFixedRate:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByFixedRate:" + DateUtils.dateFormat());
    }

    @Scheduled(fixedDelay = 10000) //每10秒執行一次
    public void scheduledTaskByFixedDelay() {
        LoggerUtils.info("定時任務開始 ByFixedDelay:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByFixedDelay:" + DateUtils.dateFormat());
    }

    private void scheduledTask() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

然後項目啟動類上增加注解@EnableScheduling,表示開啟定時任務

package cn.wbnull.springbootdemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class SpringBootDemoApplication {

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

這裡因為我們在ScheduledTask類建立了三個定時任務,@Scheduled預設是不并發執行的,是以我們先注釋掉其他,分别進行測試。

1.1 @Scheduled(cron = “0/10 * * * * ?”)

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

    @Scheduled(cron = "0/10 * * * * ?") //每10秒執行一次
    public void scheduledTaskByCorn() {
        LoggerUtils.info("定時任務開始 ByCorn:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByCorn:" + DateUtils.dateFormat());
    }

    private void scheduledTask() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-18 16:08:40,095]||定時任務開始 ByCorn:2019-02-18 16:08:40
[INFO][2019-02-18 16:08:45,097]||定時任務結束 ByCorn:2019-02-18 16:08:45
[INFO][2019-02-18 16:08:50,001]||定時任務開始 ByCorn:2019-02-18 16:08:50
[INFO][2019-02-18 16:08:55,003]||定時任務結束 ByCorn:2019-02-18 16:08:55
[INFO][2019-02-18 16:09:00,002]||定時任務開始 ByCorn:2019-02-18 16:09:00
[INFO][2019-02-18 16:09:05,004]||定時任務結束 ByCorn:2019-02-18 16:09:05
[INFO][2019-02-18 16:09:10,001]||定時任務開始 ByCorn:2019-02-18 16:09:10
[INFO][2019-02-18 16:09:15,003]||定時任務結束 ByCorn:2019-02-18 16:09:15
[INFO][2019-02-18 16:09:20,001]||定時任務開始 ByCorn:2019-02-18 16:09:20
[INFO][2019-02-18 16:09:25,002]||定時任務結束 ByCorn:2019-02-18 16:09:25
[INFO][2019-02-18 16:09:30,001]||定時任務開始 ByCorn:2019-02-18 16:09:30
[INFO][2019-02-18 16:09:35,002]||定時任務結束 ByCorn:2019-02-18 16:09:35
           

我們再改下scheduledTask方法中線程休眠時間,使休眠時間大于定時任務間隔時間Thread.sleep(12000);,然後啟動項目,檢視運作結果。

[INFO][2019-02-18 16:14:20,080]||定時任務開始 ByCorn:2019-02-18 16:14:20
[INFO][2019-02-18 16:14:32,081]||定時任務結束 ByCorn:2019-02-18 16:14:32
[INFO][2019-02-18 16:14:40,001]||定時任務開始 ByCorn:2019-02-18 16:14:40
[INFO][2019-02-18 16:14:52,002]||定時任務結束 ByCorn:2019-02-18 16:14:52
[INFO][2019-02-18 16:15:00,000]||定時任務開始 ByCorn:2019-02-18 16:15:00
[INFO][2019-02-18 16:15:12,002]||定時任務結束 ByCorn:2019-02-18 16:15:12
           

我們可以看到,對于cron表達式 來說,如果業務代碼執行時間小于定時任務間隔時間,那麼定時任務每10秒執行一次,且不受業務代碼影響,無論業務代碼執行多久,定時任務都是10秒執行一次;

如果業務代碼執行時間大于定時任務間隔時間,因定時任務預設不并發,是以一直到業務代碼執行完成的那個10秒,定時任務也是整10秒執行一次,不受業務代碼影響。

注意:@Scheduled(cron = “0/10 * * * * ?”)控制的每10秒執行一次的定時任務,是每10秒整執行一次,即一分鐘内,如果目前秒數能夠整除10,則執行定時任務,或了解為每分鐘0秒開始執行,10秒後執行下一次,執行完一分鐘後,再從0秒開始。即隻會在10s,20s,30s…的時候執行,如果配置定時任務@Scheduled(cron = “0/7 * * * * ?”)這種,則隻會在0s,7s,14s…的時候執行。

1.2 @Scheduled(fixedRate = 10000)

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

    @Scheduled(fixedRate = 10000) //每10秒執行一次
    public void scheduledTaskByFixedRate() {
        LoggerUtils.info("定時任務開始 ByFixedRate:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByFixedRate:" + DateUtils.dateFormat());
    }

    private void scheduledTask() {
        try {
            Thread.sleep(12000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-18 17:33:18,235]||定時任務開始 ByFixedRate:2019-02-18 17:33:18
[INFO][2019-02-18 17:33:23,239]||定時任務結束 ByFixedRate:2019-02-18 17:33:23
[INFO][2019-02-18 17:33:28,191]||定時任務開始 ByFixedRate:2019-02-18 17:33:28
[INFO][2019-02-18 17:33:33,195]||定時任務結束 ByFixedRate:2019-02-18 17:33:33
[INFO][2019-02-18 17:33:38,189]||定時任務開始 ByFixedRate:2019-02-18 17:33:38
[INFO][2019-02-18 17:33:43,191]||定時任務結束 ByFixedRate:2019-02-18 17:33:43
[INFO][2019-02-18 17:33:48,184]||定時任務開始 ByFixedRate:2019-02-18 17:33:48
[INFO][2019-02-18 17:33:53,186]||定時任務結束 ByFixedRate:2019-02-18 17:33:53
[INFO][2019-02-18 17:33:58,190]||定時任務開始 ByFixedRate:2019-02-18 17:33:58
[INFO][2019-02-18 17:34:03,193]||定時任務結束 ByFixedRate:2019-02-18 17:34:03
           

我們再改下scheduledTask方法中線程休眠時間,使休眠時間大于定時任務間隔時間Thread.sleep(12000);,然後啟動項目,檢視運作結果。

[INFO][2019-02-18 17:31:30,122]||定時任務開始 ByFixedRate:2019-02-18 17:31:30
[INFO][2019-02-18 17:31:42,122]||定時任務結束 ByFixedRate:2019-02-18 17:31:42
[INFO][2019-02-18 17:31:42,123]||定時任務開始 ByFixedRate:2019-02-18 17:31:42
[INFO][2019-02-18 17:31:54,123]||定時任務結束 ByFixedRate:2019-02-18 17:31:54
[INFO][2019-02-18 17:31:54,124]||定時任務開始 ByFixedRate:2019-02-18 17:31:54
[INFO][2019-02-18 17:32:06,127]||定時任務結束 ByFixedRate:2019-02-18 17:32:06
[INFO][2019-02-18 17:32:06,127]||定時任務開始 ByFixedRate:2019-02-18 17:32:06
[INFO][2019-02-18 17:32:18,134]||定時任務結束 ByFixedRate:2019-02-18 17:32:18
           

對于fixedRate 來說,如果業務代碼執行時間小于定時任務間隔時間,那麼定時任務每10秒執行一次,且不受業務代碼影響,無論業務代碼執行多久,定時任務都是10秒執行一次;

如果業務代碼執行時間大于定時任務間隔時間,則定時任務循環執行。

1.3 @Scheduled(fixedDelay = 10000)

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

    @Scheduled(fixedDelay = 10000) //每10秒執行一次
    public void scheduledTaskByFixedDelay() {
        LoggerUtils.info("定時任務開始 ByFixedDelay:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務結束 ByFixedDelay:" + DateUtils.dateFormat());
    }

    private void scheduledTask() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-18 17:45:30,784]||定時任務開始 ByFixedDelay:2019-02-18 17:45:30
[INFO][2019-02-18 17:45:35,792]||定時任務結束 ByFixedDelay:2019-02-18 17:45:35
[INFO][2019-02-18 17:45:45,803]||定時任務開始 ByFixedDelay:2019-02-18 17:45:45
[INFO][2019-02-18 17:45:50,812]||定時任務結束 ByFixedDelay:2019-02-18 17:45:50
[INFO][2019-02-18 17:46:00,814]||定時任務開始 ByFixedDelay:2019-02-18 17:46:00
[INFO][2019-02-18 17:46:05,817]||定時任務結束 ByFixedDelay:2019-02-18 17:46:05
[INFO][2019-02-18 17:46:15,821]||定時任務開始 ByFixedDelay:2019-02-18 17:46:15
[INFO][2019-02-18 17:46:20,825]||定時任務結束 ByFixedDelay:2019-02-18 17:46:20
[INFO][2019-02-18 17:46:30,829]||定時任務開始 ByFixedDelay:2019-02-18 17:46:30
[INFO][2019-02-18 17:46:35,834]||定時任務結束 ByFixedDelay:2019-02-18 17:46:35
           

我們再改下scheduledTask方法中線程休眠時間,使休眠時間大于定時任務間隔時間Thread.sleep(12000);,然後啟動項目,檢視運作結果。

[INFO][2019-02-18 17:47:06,871]||定時任務開始 ByFixedDelay:2019-02-18 17:47:06
[INFO][2019-02-18 17:47:18,879]||定時任務結束 ByFixedDelay:2019-02-18 17:47:18
[INFO][2019-02-18 17:47:28,890]||定時任務開始 ByFixedDelay:2019-02-18 17:47:28
[INFO][2019-02-18 17:47:40,896]||定時任務結束 ByFixedDelay:2019-02-18 17:47:40
[INFO][2019-02-18 17:47:50,903]||定時任務開始 ByFixedDelay:2019-02-18 17:47:50
[INFO][2019-02-18 17:48:02,911]||定時任務結束 ByFixedDelay:2019-02-18 17:48:02
[INFO][2019-02-18 17:48:12,917]||定時任務開始 ByFixedDelay:2019-02-18 17:48:12
[INFO][2019-02-18 17:48:24,924]||定時任務結束 ByFixedDelay:2019-02-18 17:48:24
           

對于fixedDelay 來說,不管業務代碼執行時間與定時任務間隔時間熟長熟短,定時任務都會等業務代碼執行完成後再開啟新一輪定時。

不過,一般大家在使用定時任務時,都是定時任務時間間隔大于業務代碼執行時間。

1.4 多說一點

對于固定時間執行的定時任務,比如每天淩晨4點執行,隻能使用cron表達式的方式

2. corn表達式

2.1 corn表達式格式

corn表達式格式:秒 分 時 日 月 星期 年(可選)

字段名 允許的值 允許的特殊字元
0-59 , - * /
0-59 , - * /
0-23 , - * /
1-31 , - * ? / L W C
1-12 或 JAN-DEC , - * /
星期 1-7 或 SUN-SAT , - * ? / L C #
年(可選) 空 或 1970-2099 , - * /

釋義:

1、*:通配符,表示該字段可以接收任意值。

2、? :表示不确定的值,或不關心它為何值,僅在日期和星期中使用,當其中一個設定了條件時,另外一個用"?" 來表示"任何值"。

3、,:表示多個值,附加一個生效的值。

4、-:表示一個指定的範圍

5、/:指定一個值的增量值。例n/m表示從n開始,每次增加m

6、L:用在日期表示當月的最後一天,用在星期"L"單獨使用時就等于"7"或"SAT",如果和數字聯合使用表示該月最後一個星期X。例如,"0L"表示該月最後一個星期日。

7、W:指定離給定日期最近的工作日(周一到周五),可以用"LW"表示該月最後一個工作日。例如,"10W"表示這個月離10号最近的工作日

8、C:表示和calendar聯系後計算過的值。例如:用在日期中,"5C"表示該月第5天或之後包括calendar的第一天;用在星期中,"5C"表示這周四或之後包括calendar的第 一天。

9、#:表示該月第幾個星期X。例6#3表示該月第三個周五。

2.2 示例值

0 * * * * ? 每分鐘觸發

0 0 * * * ? 每小時整觸發

0 0 4 * * ? 每天淩晨4點觸發

0 15 10 * * ? 每天早上10:15觸發

*/5 * * * * ? 每隔5秒觸發

0 */5 * * * ? 每隔5分鐘觸發

0 0 4 1 * ? 每月1号淩晨4點觸發

0 0 4 L * ? 每月最後一天淩晨3點觸發

0 0 3 ? * L 每周星期六淩晨3點觸發

0 11,22,33 * * * ? 每小時11分、22分、33分觸發

3. 配置定時任務

對于上面那些簡單的定時任務,定時任務的corn表達式寫死在代碼裡,如果要改動表達式,需要修改代碼,重新打包釋出,比較麻煩。是以,我們可以把corn表達式配置在配置檔案中,然後程式讀取配置,當需要修改表達式時,隻需要修改配置檔案即可。

application.yml增加配置

demo:
  corn: 0/11 * * * * ?
           

定時任務

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTask {

    @Scheduled(cron = "${demo.corn}")
    public void scheduledTaskByConfig() {
        LoggerUtils.info("定時任務 ByConfig:" + DateUtils.dateFormat());
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-18 23:47:33,047]||定時任務 ByConfig:2019-02-18 23:47:33
[INFO][2019-02-18 23:47:44,003]||定時任務 ByConfig:2019-02-18 23:47:44
[INFO][2019-02-18 23:47:55,009]||定時任務 ByConfig:2019-02-18 23:47:55
[INFO][2019-02-18 23:48:00,008]||定時任務 ByConfig:2019-02-18 23:48:00
[INFO][2019-02-18 23:48:11,009]||定時任務 ByConfig:2019-02-18 23:48:11
[INFO][2019-02-18 23:48:22,009]||定時任務 ByConfig:2019-02-18 23:48:22
[INFO][2019-02-18 23:48:33,009]||定時任務 ByConfig:2019-02-18 23:48:33
           

修改application.yml配置

demo:
  corn: 0/23 * * * * ?
           

啟動項目,運作結果如下

[INFO][2019-02-18 23:52:23,089]||定時任務 ByConfig:2019-02-18 23:52:23
[INFO][2019-02-18 23:52:46,008]||定時任務 ByConfig:2019-02-18 23:52:46
[INFO][2019-02-18 23:53:00,009]||定時任務 ByConfig:2019-02-18 23:53:00
[INFO][2019-02-18 23:53:23,002]||定時任務 ByConfig:2019-02-18 23:53:23
[INFO][2019-02-18 23:53:46,009]||定時任務 ByConfig:2019-02-18 23:53:46
           

定時任務根據配置檔案動态變化。

4. 動态修改定時任務

對于有些情況,我們需要在代碼中,通過方法動态修改定時任務corn表達式

application.yml配置

demo:
  corn: 0/7 * * * * ?
  cornV2: 0/22 * * * * ?
           

建立ScheduledTaskV2.java

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

@Component
public class ScheduledTaskV2 implements SchedulingConfigurer {

    @Value("${demo.corn}")
    private String corn;
    @Value("${demo.cornV2}")
    private String cornV2;

    private int tag = 0;

    @Override
    public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
        scheduledTaskRegistrar.addTriggerTask(() -> {
            LoggerUtils.info("定時任務V2:" + DateUtils.dateFormat());
        }, (triggerContext) -> {
            CronTrigger cronTrigger;
            if (tag % 2 == 0) {
                LoggerUtils.info("定時任務V2動态修改corn表達式:" + corn + "," + DateUtils.dateFormat());
                cronTrigger = new CronTrigger(corn);
                tag++;
            } else {
                LoggerUtils.info("定時任務V2動态修改corn表達式:" + cornV2 + "," + DateUtils.dateFormat());
                cronTrigger = new CronTrigger(cornV2);
                tag++;
            }

            return cronTrigger.nextExecutionTime(triggerContext);
        });
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-19 00:19:49,011]||定時任務V2:2019-02-19 00:19:49
[INFO][2019-02-19 00:19:49,011]||定時任務V2動态修改corn表達式:0/22 * * * * ?,2019-02-19 00:19:49
[INFO][2019-02-19 00:20:00,007]||定時任務V2:2019-02-19 00:20:00
[INFO][2019-02-19 00:20:00,007]||定時任務V2動态修改corn表達式:0/7 * * * * ?,2019-02-19 00:20:00
[INFO][2019-02-19 00:20:07,006]||定時任務V2:2019-02-19 00:20:07
[INFO][2019-02-19 00:20:07,006]||定時任務V2動态修改corn表達式:0/22 * * * * ?,2019-02-19 00:20:07
[INFO][2019-02-19 00:20:22,008]||定時任務V2:2019-02-19 00:20:22
[INFO][2019-02-19 00:20:22,008]||定時任務V2動态修改corn表達式:0/7 * * * * ?,2019-02-19 00:20:22
[INFO][2019-02-19 00:20:28,010]||定時任務V2:2019-02-19 00:20:28
[INFO][2019-02-19 00:20:28,010]||定時任務V2動态修改corn表達式:0/22 * * * * ?,2019-02-19 00:20:28
[INFO][2019-02-19 00:20:44,003]||定時任務V2:2019-02-19 00:20:44
[INFO][2019-02-19 00:20:44,003]||定時任務V2動态修改corn表達式:0/7 * * * * ?,2019-02-19 00:20:44
[INFO][2019-02-19 00:20:49,004]||定時任務V2:2019-02-19 00:20:49
[INFO][2019-02-19 00:20:49,004]||定時任務V2動态修改corn表達式:0/22 * * * * ?,2019-02-19 00:20:49
[INFO][2019-02-19 00:21:00,011]||定時任務V2:2019-02-19 00:21:00
[INFO][2019-02-19 00:21:00,011]||定時任務V2動态修改corn表達式:0/7 * * * * ?,2019-02-19 00:21:00
[INFO][2019-02-19 00:21:07,011]||定時任務V2:2019-02-19 00:21:07
[INFO][2019-02-19 00:21:07,011]||定時任務V2動态修改corn表達式:0/22 * * * * ?,2019-02-19 00:21:07
           

成功通過代碼動态修改corn表達式且運作結果正确。

5. 并發執行定時任務

回到我們 1. 簡單定時任務 中建立的三個定時任務,當時因為@Scheduled預設是不并發執行的,是以我們先注釋掉了其他定時任務,分别進行的測試。

那我們實際開發中,确實建立了多個定時任務,且想并發執行時,該怎麼做呢?

定時任務類添加注解@EnableAsync,需并發執行的定時任務方法添加注解@Async

建立定時任務類ScheduledTaskV3

package cn.wbnull.springbootdemo.schedule;

import cn.wbnull.springbootdemo.util.DateUtils;
import cn.wbnull.springbootdemo.util.LoggerUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@EnableAsync
public class ScheduledTaskV3 {

    @Scheduled(cron = "0/7 * * * * ?")
    @Async
    public void scheduledTaskV1() {
        LoggerUtils.info("定時任務V3,定時任務1開始:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務V3,定時任務1結束:" + DateUtils.dateFormat());
    }

    @Scheduled(cron = "0/10 * * * * ?")
    @Async
    public void scheduledTaskV2() {
        LoggerUtils.info("定時任務V3,定時任務2開始:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務V3,定時任務2結束:" + DateUtils.dateFormat());
    }

    @Scheduled(cron = "0/22 * * * * ?")
    @Async
    public void scheduledTaskV3() {
        LoggerUtils.info("定時任務V3,定時任務3開始:" + DateUtils.dateFormat());
        scheduledTask();
        LoggerUtils.info("定時任務V3,定時任務3結束:" + DateUtils.dateFormat());
    }

    private void scheduledTask() {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
           

啟動項目,運作結果如下

[INFO][2019-02-19 00:36:21,077]||定時任務V3,定時任務1開始:2019-02-19 00:36:21
[INFO][2019-02-19 00:36:22,003]||定時任務V3,定時任務3開始:2019-02-19 00:36:22
[INFO][2019-02-19 00:36:26,078]||定時任務V3,定時任務1結束:2019-02-19 00:36:26
[INFO][2019-02-19 00:36:27,006]||定時任務V3,定時任務3結束:2019-02-19 00:36:27
[INFO][2019-02-19 00:36:28,003]||定時任務V3,定時任務1開始:2019-02-19 00:36:28
[INFO][2019-02-19 00:36:30,003]||定時任務V3,定時任務2開始:2019-02-19 00:36:30
[INFO][2019-02-19 00:36:33,003]||定時任務V3,定時任務1結束:2019-02-19 00:36:33
[INFO][2019-02-19 00:36:35,004]||定時任務V3,定時任務1開始:2019-02-19 00:36:35
[INFO][2019-02-19 00:36:35,005]||定時任務V3,定時任務2結束:2019-02-19 00:36:35
[INFO][2019-02-19 00:36:40,003]||定時任務V3,定時任務2開始:2019-02-19 00:36:40
[INFO][2019-02-19 00:36:40,005]||定時任務V3,定時任務1結束:2019-02-19 00:36:40
[INFO][2019-02-19 00:36:42,001]||定時任務V3,定時任務1開始:2019-02-19 00:36:42
[INFO][2019-02-19 00:36:44,003]||定時任務V3,定時任務3開始:2019-02-19 00:36:44
[INFO][2019-02-19 00:36:45,004]||定時任務V3,定時任務2結束:2019-02-19 00:36:45
[INFO][2019-02-19 00:36:47,002]||定時任務V3,定時任務1結束:2019-02-19 00:36:47
[INFO][2019-02-19 00:36:49,002]||定時任務V3,定時任務1開始:2019-02-19 00:36:49
[INFO][2019-02-19 00:36:49,004]||定時任務V3,定時任務3結束:2019-02-19 00:36:49
[INFO][2019-02-19 00:36:50,001]||定時任務V3,定時任務2開始:2019-02-19 00:36:50
           

定時任務能夠并發執行。

GitHub:https://github.com/dkbnull/SpringBootDemo

微信:https://mp.weixin.qq.com/s/qJZpCjcZYQWnmDkztiA_uQ

微網誌:https://weibo.com/ttarticle/p/show?id=2309404446645717696521

知乎:https://zhuanlan.zhihu.com/p/95813468