在企業級應用中,會常常指定一些計劃任務,即在某個時間點作某件事情,核心是以時間爲關注點,即在一個特定的時間點,系統執行特定的一個操做,常見的任務調度框架有Quartz和SpringTask等。其中SpringTask是spring在spring3後自帶支持的定時任務。下面的demo講述的就是SpringTask。spring
1 @EnableScheduling 2 @SpringBootApplication 3 public class SpringTaskApplication { 4 5 public static void main(String[] args) { 6 SpringApplication.run(SpringTaskApplication.class, args); 7 } 8 }
1 @Component 2 public class SpringTaskDemo { 3 /** 4 * 定時刷新 5 */ 6 /** 7 * @Scheduled(fixedRate = 5000) //上次執行開始時間後5秒執行 8 * @Scheduled(fixedDelay = 5000) //上次執行完畢後5秒執行 9 * @Scheduled(initialDelay=3000, fixedRate=5000) //第一次延遲3秒,之後每隔5秒執行一次 10 */ 11 @Scheduled(cron = "* * * * * ?") 12 public void task01() throws InterruptedException { 13 System.out.println("開始執行了任務調度task01" + new Date()); 14 Thread.sleep(5000); 15 System.out.println("結束執行了任務調度task01" + new Date()); 16 } 17 }
注:上面的任務執行打印開始結束,以及中間的線程休眠時間,主要是爲了展現串行並行過程的效果。多線程
格式:Cron表達式是一個字符串,字符串以5或6個空格隔開,分爲6或7個域,每個域表明一個含義,Cron有以下兩種語法格式:框架
(1)Seconds Minutes Hours DayofMonth Month DayofWeek Yearide
(2)Seconds Minutes Hours DayofMonth Month DayofWeek測試
每個域可出現的字符以下:spa
Seconds:可出現", - * /"四個字符,有效範圍爲0-59的整數線程
Minutes:可出現", - * /"四個字符,有小範圍爲0-59的整數3d
Hours:可出現", - * /"四個字符,有效範圍爲0-23的整數code
DayofMonth:可出現", - * / ? L W C"八個字符,有效範圍爲1-31的整數xml
Month:可出現", - * /"四個字符,有效範圍爲1-12的整數或JAN-DEC(月份的簡稱)
DayofWeek:可出現", - * / ? L C #"八個字符,有效範圍爲1-7的整數或SUN-SAT(星期的簡稱)兩個範圍,1表示星期天,2表示星期一,依次類推
YEAR:可出現", - * /"四個字符,有效範圍是1970-2099年
(1),:表示列出枚舉值,例如,在Minutes域使用"5,20"。則意味着在5和20分每分鐘觸發一次;
(2)-:表示範圍,例如在Minutes域使用"5-20",表示從5分到20分每分鐘觸發一次;
(3)*:表示匹配該域的任意值,假如在Minutes域中使用"*「,表示每分鐘都會觸發事件;
(4)/:表示起始時間開始觸發,而後每隔固定時間觸發一下,例如在Minutes域中使用5/20,則意味着第5分鐘觸發一次,而後第25分,45分觸發一次;
-----------------------------如下符號只能出如今DayofMonth和DayofWeek兩個域-----------------------------
(5)?:它也匹配任意值,但其實不會。由於DayofMonth和DayofWeek會相互影響。例如想在每個月的20日觸發調度,無論是20日究竟是星期幾,兩個位置當一個位置取一個特定含義的值後另一個位置只能用?佔位,例如:12 12 15 20 * ?;
(6)L:表示最後,例如在DayofWeek域使用5L,意味着在最後的一個星期四觸發;
---------------------------------------------------------分割線---------------------------------------------------------
(7)W:表示有效工做日(週一到週五),只能出如今DayofMonth域中,系統將在離指定日期的最近的有效工做日觸發事件。例如:在DayofMonth使用5W,若是5日是星期六,則在最近的工做日:星期五,即4日觸發。若是5日是星期天,則在6日(週一)觸發;若是5日在星期一到週五中的一天,,則就在5日觸發。另一點,W的最近尋找不會跨過月份;
(8)#:用於肯定第幾個月的第幾個星期幾,只能出如今DayofWeek域,例如:4#2,表示某月的第二個星期三。
參看task01定義task02方法,此時任務公用兩個任務方法
1 /** 2 * 上次執行開始時間後5秒執行 3 * @throws InterruptedException 4 */ 5 @Scheduled(fixedRate = 5000) 6 public void task02() throws InterruptedException { 7 System.out.println("開始執行了任務調度task02" + new Date()); 8 Thread.sleep(5000); 9 System.out.println("結束執行了任務調度task02" + new Date()); 10 }
測試發現,兩個方法由一個線程串行執行,task01方法執行完成task02再執行
咱們發現有時候在項目中咱們須要多個不一樣的任務並行的執行,下面執行配置線程池實現多線程調度任務。取消SpringBoot啓動類上的@EnableScheduling註解
1 @Configuration 2 @EnableScheduling 3 public class SpringTaskParallelDemo implements SchedulingConfigurer,AsyncConfigurer{ 4 @Bean 5 public ThreadPoolTaskScheduler taskScheduler(){ 6 ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); 7 // 初始化線程池 8 scheduler.initialize(); 9 // 線程池容量 10 int corePoolSize = 5; 11 scheduler.setPoolSize(corePoolSize); 12 return scheduler; 13 } 14 15 @Override 16 public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { 17 scheduledTaskRegistrar.setTaskScheduler(taskScheduler()); 18 } 19 20 @Override 21 public Executor getAsyncExecutor() { 22 return taskScheduler(); 23 } 24 25 @Override 26 public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { 27 return null; 28 } 29 }
測試,發現兩個任務由不一樣的線程並行執行,互不影響。