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