SpringBoot最簡單的定時任務(wù)@Scheduler的使用及解讀
SpringBoot定時任務(wù)@Scheduler
Spring Boot 中一般來說定時任務(wù)使用@Scheduler注解或者Quartz框架,或者自定義線程實現(xiàn),最簡單的當屬@Scheduler注解
- 依賴:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.3.RELEASE</version> </dependency>
- 創(chuàng)建Application:
@SpringBootApplication //此注解開啟異步定時任務(wù),必須要有 @EnableScheduling public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } }
- 創(chuàng)建任務(wù):
@Component public class SpringJob { //springboot掃描到這個注解就會按照定義的計劃去執(zhí)行任務(wù) //cron是cron表達式,因為很簡單但是描述要話費比較多的篇幅,所以略 @Scheduled(cron = "0/1 * * * * ?") public void myJob(){ //任務(wù)處理邏輯 System.out.println(new Date() +"Spring Scheduler 執(zhí)行"); } }
- 啟動 Application:
上述是一個最簡單的單job cron調(diào)度的實現(xiàn).
- @Scheduler中的參數(shù):
String cron() default ""; String zone() default ""; long fixedDelay() default -1; String fixedDelayString() default ""; long fixedRate() default -1; String fixedRateString() default ""; long initialDelay() default -1; String initialDelayString() default "";
String cron() default “”;接收一個cron表達式字符串,以cron表達式調(diào)度任務(wù) String zone() default “”;設(shè)置時區(qū),不設(shè)置的話cron就基于服務(wù)器所在的本地時區(qū) long fixedDelay() default -1;設(shè)置任務(wù)間隔時間(毫秒),就是任務(wù)結(jié)束后再過多久開始新的任務(wù) String fixedDelayString() default “”;同 long fixedDelay(),只是把參數(shù)從long改成string long fixedRate() default -1;設(shè)置任務(wù)每隔多久開啟 String fixedRateString() default “”;同 long fixedRate() 只是把參數(shù)從long改成string long initialDelay() default -1;第一次執(zhí)行延遲時間(啟動后多久才開始任務(wù)) String initialDelayString() default “”;同 long initialDelay()
- spring boot 默認開啟一個線程執(zhí)行任務(wù):
@Component public class SpringJob { @Scheduled(fixedRateString = "1000") public void myJob2() throws InterruptedException { System.out.println(new Date() +" job開啟"); Thread.sleep(2000); System.out.println(new Date() +" job結(jié)束"); } } 執(zhí)行結(jié)果: Fri Jul 31 10:34:16 CST 2020 job開啟 Fri Jul 31 10:34:18 CST 2020 job結(jié)束 Fri Jul 31 10:34:18 CST 2020 job開啟 Fri Jul 31 10:34:20 CST 2020 job結(jié)束 Fri Jul 31 10:34:20 CST 2020 job開啟 Fri Jul 31 10:34:22 CST 2020 job結(jié)束 Fri Jul 31 10:34:22 CST 2020 job開啟 Fri Jul 31 10:34:24 CST 2020 job結(jié)束 Fri Jul 31 10:34:24 CST 2020 job開啟 Fri Jul 31 10:34:26 CST 2020 job結(jié)束 Fri Jul 31 10:34:26 CST 2020 job開啟 Fri Jul 31 10:34:28 CST 2020 job結(jié)束 Fri Jul 31 10:34:28 CST 2020 job開啟 Fri Jul 31 10:34:30 CST 2020 job結(jié)束
設(shè)置的任務(wù)為每隔1秒中開啟一次,一次任務(wù)執(zhí)行時間是2秒,但是發(fā)現(xiàn)執(zhí)行的過程是,同一時間只有一個線程在執(zhí)行.也就是單線程執(zhí)行
- 現(xiàn)在執(zhí)行兩個job,單線程情況下,自然也是無法并發(fā)的:
@Component public class SpringJob { @Scheduled(fixedRateString = "2000") public void myJob() throws InterruptedException { System.out.println(new Date() +" job1開始"); Thread.sleep(10000); System.out.println(new Date() +" job1結(jié)束"); } @Scheduled(fixedRateString = "1000") public void myJob2() throws InterruptedException { System.out.println(new Date() +" job2開啟"); Thread.sleep(2000); System.out.println(new Date() +" job2結(jié)束"); } } 執(zhí)行結(jié)果: Fri Jul 31 10:51:56 CST 2020 job1開始 Fri Jul 31 10:52:06 CST 2020 job1結(jié)束 Fri Jul 31 10:52:06 CST 2020 job2開啟 Fri Jul 31 10:52:08 CST 2020 job2結(jié)束 Fri Jul 31 10:52:08 CST 2020 job2開啟 Fri Jul 31 10:52:10 CST 2020 job2結(jié)束 Fri Jul 31 10:52:10 CST 2020 job1開始 Fri Jul 31 10:52:20 CST 2020 job1結(jié)束 Fri Jul 31 10:52:20 CST 2020 job2開啟 Fri Jul 31 10:52:22 CST 2020 job2結(jié)束 Fri Jul 31 10:52:22 CST 2020 job2開啟 Fri Jul 31 10:52:24 CST 2020 job2結(jié)束
任務(wù)的每次執(zhí)行,無論是單個任務(wù)多次執(zhí)行,還是多個任務(wù)一次執(zhí)行,對于線程來說都是一樣的,都需要開啟一個線程.有幾個線程就可以幾個任務(wù)(或者相同任務(wù)的多次)并發(fā)執(zhí)行
默認情況下,scheduler只有一個線程
- 自定義線程池,添加一個配置類:
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(setExecutor()); } @Bean public Executor setExecutor() { //設(shè)置線程個數(shù),這里我們設(shè)置5個(同一時間可以并行執(zhí)行5個線程) return Executors.newScheduledThreadPool(5); } }
- 此時執(zhí)行上方的單個任務(wù):
Fri Jul 31 10:55:18 CST 2020 job開啟
Fri Jul 31 10:55:20 CST 2020 job結(jié)束
Fri Jul 31 10:55:20 CST 2020 job開啟
Fri Jul 31 10:55:22 CST 2020 job結(jié)束
Fri Jul 31 10:55:22 CST 2020 job開啟
Fri Jul 31 10:55:24 CST 2020 job結(jié)束
Fri Jul 31 10:55:24 CST 2020 job開啟
Fri Jul 31 10:55:26 CST 2020 job結(jié)束
單個任務(wù)還是只能串行執(zhí)行.
- 執(zhí)行上方的兩個任務(wù):
Fri Jul 31 10:59:59 CST 2020 job2開啟
Fri Jul 31 10:59:59 CST 2020 job1開始
Fri Jul 31 11:00:01 CST 2020 job2結(jié)束
Fri Jul 31 11:00:01 CST 2020 job2開啟
Fri Jul 31 11:00:03 CST 2020 job2結(jié)束
Fri Jul 31 11:00:03 CST 2020 job2開啟
Fri Jul 31 11:00:05 CST 2020 job2結(jié)束
Fri Jul 31 11:00:05 CST 2020 job2開啟
Fri Jul 31 11:00:07 CST 2020 job2結(jié)束
Fri Jul 31 11:00:07 CST 2020 job2開啟
Fri Jul 31 11:00:09 CST 2020 job1結(jié)束
Fri Jul 31 11:00:09 CST 2020 job1開始
Fri Jul 31 11:00:09 CST 2020 job2結(jié)束
發(fā)現(xiàn)任務(wù)跟job1與job2之間是可以并發(fā)執(zhí)行的.但是對于job1的多次任務(wù),job2的多次任務(wù),都是串行執(zhí)行的.
現(xiàn)在線程池中有多個線程,job與job之間可以并發(fā),如何讓單個job的多次可以并發(fā)執(zhí)行,就需要@Async注解,此注解要用在job的方法上.@EnableAsync注解,此注解要在Application類上,此時,job的多次執(zhí)行也可以并發(fā)執(zhí)行了.
@SpringBootApplication @EnableScheduling @EnableAsync public class Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } } @Component public class SpringJob { @Async @Scheduled(fixedRateString = "2000") public void myJob() throws InterruptedException { System.out.println(new Date() + " job1開始"); Thread.sleep(10000); System.out.println(new Date() + " job1結(jié)束"); } @Scheduled(fixedRateString = "1000") public void myJob2() throws InterruptedException { System.out.println(new Date() + " job2開啟"); Thread.sleep(2000); System.out.println(new Date() + " job2結(jié)束"); } } 執(zhí)行結(jié)果: Fri Jul 31 11:08:57 CST 2020 job2開啟 Fri Jul 31 11:08:57 CST 2020 job1開始 Fri Jul 31 11:08:59 CST 2020 job1開始 Fri Jul 31 11:08:59 CST 2020 job2結(jié)束 Fri Jul 31 11:08:59 CST 2020 job2開啟 Fri Jul 31 11:09:01 CST 2020 job1開始 Fri Jul 31 11:09:01 CST 2020 job2結(jié)束 Fri Jul 31 11:09:01 CST 2020 job2開啟 Fri Jul 31 11:09:03 CST 2020 job1開始 Fri Jul 31 11:09:03 CST 2020 job2結(jié)束 Fri Jul 31 11:09:03 CST 2020 job2開啟
可以發(fā)現(xiàn)job1在前一次沒有執(zhí)行完時,就已經(jīng)開始執(zhí)行了.
重要一點
自定線程池Configuration是為了啟用多線程,此時可以起到j(luò)ob1與job2之間的并發(fā)執(zhí)行,但是job1多次任務(wù)只能串行執(zhí)行,所以才增加了@Aysnc跟@EnableAsync注解.
@EnableAsync注解有兩個作用,1單線程變多線程,2 可以允許單個job多次運行時并行執(zhí)行(需要再加@Async),如果已經(jīng)是多線程了,但是不加此注解,同一個job的多次執(zhí)行還是串行.
其實在使用@EnableAsync注解的時候,springboot會把自定義的configuration給覆蓋掉,即使在configuration中配置了單個線程,任務(wù)的并發(fā)也不會受到影響.所以推薦使用@EnableAsync來完成多線程配置再加@Aysnc來完成任務(wù)的并發(fā).
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring Boot Actuator未授權(quán)訪問漏洞的問題解決
Spring Boot Actuator 端點的未授權(quán)訪問漏洞是一個安全性問題,可能會導致未經(jīng)授權(quán)的用戶訪問敏感的應(yīng)用程序信息,本文就來介紹一下解決方法,感興趣的可以了解一下2023-09-09spring boot請求異常處理并返回對應(yīng)的html頁面
這篇文章主要介紹了spring boot處理請求異常并返回對應(yīng)的html頁面,包括404異常處理和500異常處理,需要的朋友可以參考下2017-07-07SpringBoot實現(xiàn)自定義配置文件提示的方法
這篇文章主要介紹了SpringBoot實現(xiàn)自定義配置文件提示的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-03-03java實現(xiàn)ftp上傳 如何創(chuàng)建文件夾
這篇文章主要為大家詳細介紹了java實現(xiàn)ftp上傳的相關(guān)資料,教大家如何創(chuàng)建文件夾?具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04Java中的關(guān)鍵字synchronized 詳解
這篇文章主要介紹了Java中的關(guān)鍵字synchronized,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-03-03