帶你3分鐘帶你搞定Spring Boot中Schedule
一、背景介紹
在實際的業(yè)務開發(fā)過程中,我們經常會需要定時任務來幫助我們完成一些工作,例如每天早上 6 點生成銷售報表、每晚 23 點清理臟數據等等。
如果你當前使用的是 SpringBoot 來開發(fā)項目,那么完成這些任務會非常容易!
SpringBoot 默認已經幫我們完成了相關定時任務組件的配置,我們只需要添加相應的注解@Scheduled
就可以實現任務調度!
二、方案實踐
2.1、pom 包配置
pom
包里面只需要引入Spring Boot Starter
包即可!
??????? <dependencies> <!--spring boot核心--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--spring boot 測試--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
???????2.2、啟動類啟用定時調度
在啟動類上面加上@EnableScheduling
即可開啟定時
@SpringBootApplication @EnableScheduling public class ScheduleApplication { public static void main(String[] args) { SpringApplication.run(ScheduleApplication.class, args); } }
???????2.3、創(chuàng)建定時任務
Spring Scheduler
支持四種形式的任務調度!
- fixedRate:固定速率執(zhí)行,例如每5秒執(zhí)行一次
- fixedDelay:固定延遲執(zhí)行,例如距離上一次調用成功后2秒執(zhí)行
- initialDelay:初始延遲任務,例如任務開啟過5秒后再執(zhí)行,之后以固定頻率或者間隔執(zhí)行
- cron:使用 Cron 表達式執(zhí)行定時任務
2.3.1、固定速率執(zhí)行
你可以通過使用fixedRate
參數以固定時間間隔來執(zhí)行任務,示例如下:
@Component public class SchedulerTask { private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * fixedRate:固定速率執(zhí)行。每5秒執(zhí)行一次。 */ @Scheduled(fixedRate = 5000) public void runWithFixedRate() { log.info("Fixed Rate Task,Current Thread : {},The time is now : {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } }
運行ScheduleApplication
主程序,即可看到控制臺輸出效果:
Fixed Rate Task,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:00
Fixed Rate Task,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:10
...
???????2.3.2、固定延遲執(zhí)行
你可以通過使用fixedDelay
參數來設置上一次任務調用完成與下一次任務調用開始之間的延遲時間,示例如下:
@Component public class SchedulerTask { private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * fixedDelay:固定延遲執(zhí)行。距離上一次調用成功后2秒后再執(zhí)行。 */ @Scheduled(fixedDelay = 2000) public void runWithFixedDelay() { log.info("Fixed Delay Task,Current Thread : {},The time is now : {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } }
控制臺輸出效果:
Fixed Delay Task,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:00
Fixed Delay Task,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:02
...
???????2.3.3、初始延遲任務
你可以通過使用initialDelay
參數與fixedRate
或者fixedDelay
搭配使用來實現初始延遲任務調度。
@Component public class SchedulerTask { private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * initialDelay:初始延遲。任務的第一次執(zhí)行將延遲5秒,然后將以5秒的固定間隔執(zhí)行。 */ @Scheduled(initialDelay = 5000, fixedRate = 5000) public void reportCurrentTimeWithInitialDelay() { log.info("Fixed Rate Task with Initial Delay,Current Thread : {},The time is now : {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } }
控制臺輸出效果:
Fixed Rate Task with Initial Delay,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:05
Fixed Rate Task with Initial Delay,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:10
...
???????2.3.4、使用 Cron 表達式
Spring Scheduler
同樣支持Cron
表達式,如果以上簡單參數都不能滿足現有的需求,可以使用 cron 表達式來定時執(zhí)行任務。
關于cron
表達式的具體用法,可以點擊參考這里: https://cron.qqe2.com/
@Component public class SchedulerTask { private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); /** * cron:使用Cron表達式。每6秒中執(zhí)行一次 */ @Scheduled(cron = "*/6 * * * * ?") public void reportCurrentTimeWithCronExpression() { log.info("Cron Expression,Current Thread : {},The time is now : {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } }
控制臺輸出效果:
Cron Expression,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:06
Cron Expression,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 11:46:12
...
???????2.4、異步執(zhí)行定時任務
在介紹異步執(zhí)行定時任務之前,我們先看一個例子!
在下面的示例中,我們創(chuàng)建了一個每隔2秒執(zhí)行一次的定時任務,在任務里面大概需要花費 3 秒鐘,猜猜執(zhí)行結果如何?
@Component public class AsyncScheduledTask { private static final Logger log = LoggerFactory.getLogger(AsyncScheduledTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Scheduled(fixedRate = 2000) public void runWithFixedDelay() { try { TimeUnit.SECONDS.sleep(3); log.info("Fixed Delay Task, Current Thread : {} : The time is now {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } catch (InterruptedException e) { log.error("錯誤信息",e); } } }
控制臺輸入結果:
Fixed Delay Task, Current Thread : scheduling-1 : The time is now 2020-12-15 17:55:26
Fixed Delay Task, Current Thread : scheduling-1 : The time is now 2020-12-15 17:55:31
Fixed Delay Task, Current Thread : scheduling-1 : The time is now 2020-12-15 17:55:36
Fixed Delay Task, Current Thread : scheduling-1 : The time is now 2020-12-15 17:55:41
...
很清晰的看到,任務調度頻率變成了每隔5秒調度一次!
這是為啥呢?
從Current Thread : scheduling-1
輸出結果可以很看到,任務執(zhí)行都是同一個線程!默認的情況下,@Scheduled
任務都在 Spring 創(chuàng)建的大小為 1 的默認線程池中執(zhí)行!
更直觀的結果是,任務都是串行執(zhí)行!
下面,我們將其改成異步線程來執(zhí)行,看看效果如何?
@Component @EnableAsync public class AsyncScheduledTask { private static final Logger log = LoggerFactory.getLogger(AsyncScheduledTask.class); private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Async @Scheduled(fixedDelay = 2000) public void runWithFixedDelay() { try { TimeUnit.SECONDS.sleep(3); log.info("Fixed Delay Task, Current Thread : {} : The time is now {}", Thread.currentThread().getName(), dateFormat.format(new Date())); } catch (InterruptedException e) { log.error("錯誤信息",e); } } }
控制臺輸出結果:
Fixed Delay Task, Current Thread : SimpleAsyncTaskExecutor-1 : The time is now 2020-12-15 18:55:26
Fixed Delay Task, Current Thread : SimpleAsyncTaskExecutor-2 : The time is now 2020-12-15 18:55:28
Fixed Delay Task, Current Thread : SimpleAsyncTaskExecutor-3 : The time is now 2020-12-15 18:55:30
...
任務的執(zhí)行頻率不受方法內的時間影響,以并行方式執(zhí)行!
2.5、自定義任務線程池
雖然默認的情況下,@Scheduled
任務都在 Spring 創(chuàng)建的大小為 1 的默認線程池中執(zhí)行,但是我們也可以自定義線程池,只需要實現SchedulingConfigurer
類即可!
自定義線程池示例如下:
@Configuration public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler(); //線程池大小為10 threadPoolTaskScheduler.setPoolSize(10); //設置線程名稱前綴 threadPoolTaskScheduler.setThreadNamePrefix("scheduled-thread-"); //設置線程池關閉的時候等待所有任務都完成再繼續(xù)銷毀其他的Bean threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); //設置線程池中任務的等待時間,如果超過這個時候還沒有銷毀就強制銷毀,以確保應用最后能夠被關閉,而不是阻塞住 threadPoolTaskScheduler.setAwaitTerminationSeconds(60); //這里采用了CallerRunsPolicy策略,當線程池沒有處理能力的時候,該策略會直接在 execute 方法的調用線程中運行被拒絕的任務;如果執(zhí)行程序已關閉,則會丟棄該任務 threadPoolTaskScheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); threadPoolTaskScheduler.initialize(); scheduledTaskRegistrar.setTaskScheduler(threadPoolTaskScheduler); } }
我們啟動服務,看看cron
任務示例調度效果:
Cron Expression,Current Thread : scheduled-thread-1,The time is now : 2020-12-15 20:46:00
Cron Expression,Current Thread : scheduled-thread-2,The time is now : 2020-12-15 20:46:06
Cron Expression,Current Thread : scheduled-thread-3,The time is now : 2020-12-15 20:46:12
Cron Expression,Current Thread : scheduled-thread-4,The time is now : 2020-12-15 20:46:18
....
當前線程名稱已經被改成自定義scheduled-thread
的前綴!
三、小結
本文主要圍繞Spring scheduled
應用實踐進行分享,如果是單體應用,使用SpringBoot
內置的@scheduled
注解可以解決大部分業(yè)務需求,上手非常容易!
項目源代碼地址:spring-boot-example-scheduled
四、參考
1、https://springboot.io/t/topic/2758
到此這篇關于3分鐘帶你搞定Spring Boot中Schedule 的文章就介紹到這了,更多相關Spring Boot中Schedule 內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- SpringBoot中定時任務@Scheduled的多線程使用詳解
- SpringBoot通過@Scheduled實現定時任務及單線程運行問題解決
- SpringBoot?ScheduledTaskRegistrar解決動態(tài)定時任務思路詳解
- SpringBoot定時任務動態(tài)擴展ScheduledTaskRegistrar詳解
- SpringBoot中定時任務@Scheduled注解的使用解讀
- 解決SpringBoot中的Scheduled單線程執(zhí)行問題
- SpringBoot中使用@scheduled定時執(zhí)行任務的坑
- springboot使用定時器@Scheduled不管用的解決
相關文章
SpringBoot在IDEA中實現熱部署(JRebel實用版)
這篇文章主要介紹了SpringBoot在IDEA中實現熱部署(JRebel實用版),文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-05-05java線程并發(fā)cyclicbarrier類使用示例
CyclicBarrier類似于CountDownLatch也是個計數器,不同的是CyclicBarrier數的是調用了CyclicBarrier.await()進入等待的線程數,當線程數達到了CyclicBarrier初始時規(guī)定的數目時,所有進入等待狀態(tài)的線程被喚醒并繼續(xù),下面使用示例學習他的使用方法2014-01-01