SpringBoot使用@Scheduled實現(xiàn)定時任務(wù)的并行執(zhí)行
引言
在SpringBoot中,如果使用@Scheduled注解來定義多個定時任務(wù),默認情況下這些任務(wù)將會被安排在一個單線程的調(diào)度器中執(zhí)行。這意味著,這些任務(wù)將會串行執(zhí)行,而不是并行執(zhí)行。當(dāng)一個任務(wù)正在執(zhí)行時,其他被觸發(fā)的任務(wù)將會等待當(dāng)前任務(wù)完成后再開始執(zhí)行,這可能導(dǎo)致任務(wù)執(zhí)行上的阻塞,特別是當(dāng)某個任務(wù)執(zhí)行時間較長時,可能會延遲后續(xù)任務(wù)的啟動時間,影響定時任務(wù)的準時性。
1.問題代碼及測試結(jié)果
問題代碼:
@Scheduled(cron = "*/1 * * * * *") public void a() throws InterruptedException { log.info("A Start {}!", System.currentTimeMillis()); Thread.sleep(2000); log.info("A End {}!", System.currentTimeMillis()); } @Scheduled(cron = "*/1 * * * * *") public void b() { log.info("B Start {}!", System.currentTimeMillis()); log.info("B End {}!", System.currentTimeMillis()); }
部分測試結(jié)果:
15:38:29.001 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716968309001! 15:38:29.001 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716968309001! 15:38:29.001 [scheduling-1] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716968309001! 15:38:31.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716968311003! 15:38:31.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716968311003! 15:38:31.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716968311003! 15:38:32.002 [scheduling-1] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716968312002! 15:38:34.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716968314003! 15:38:34.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716968314003! 15:38:34.003 [scheduling-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716968314003!
結(jié)果分析:
- A和B是串行的。
2.定時任務(wù)實現(xiàn)并行
2.1 使用自定義線程池(添加類)
可以通過配置一個自定義的TaskScheduler
或者ThreadPoolTaskScheduler
來為@Scheduled
任務(wù)提供一個線程池,從而允許多個任務(wù)并行執(zhí)行。例如,可以在配置類中定義一個ThreadPoolTaskScheduler
Bean:
@Configuration public class AsyncConfig { @Bean public ThreadPoolTaskScheduler taskScheduler() { ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler(); // 設(shè)置線程池大小 scheduler.setPoolSize(10); scheduler.setThreadNamePrefix("my-scheduled-task-"); return scheduler; } }
并確保你的配置類被掃描到,且在@EnableScheduling
注解的上下文中。
測試代碼:
@Scheduled(cron = "*/1 * * * * *") public void a() throws InterruptedException { log.info("A Start {}!", System.currentTimeMillis()); Thread.sleep(2000); log.info("A End {}!", System.currentTimeMillis()); } @Scheduled(cron = "*/1 * * * * *") public void b() { log.info("B Start {}!", System.currentTimeMillis()); log.info("B End {}!", System.currentTimeMillis()); }
部分測試結(jié)果:
15:16:18.003 [my-scheduled-task-2] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716966978003! 15:16:18.003 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966978003! 15:16:18.003 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966978003! 15:16:19.002 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966979002! 15:16:19.002 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966979002! 15:16:20.004 [my-scheduled-task-2] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716966980004! 15:16:20.004 [my-scheduled-task-3] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966980004! 15:16:20.004 [my-scheduled-task-3] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966980004! 15:16:21.003 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716966981003! 15:16:21.003 [my-scheduled-task-4] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966981003! 15:16:21.003 [my-scheduled-task-4] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966981003! 15:16:22.001 [my-scheduled-task-2] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966982001! 15:16:22.001 [my-scheduled-task-2] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966982001! 15:16:23.004 [my-scheduled-task-1] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716966983004! 15:16:23.004 [my-scheduled-task-3] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716966983004! 15:16:23.004 [my-scheduled-task-3] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716966983004!
結(jié)果分析:
- A和B是并行的;
- A和A或者B和B是串行的。
2.2 使用異步處理(添加類和注解)
結(jié)合@Async
注解和@EnableAsync可以使得每個@Scheduled任務(wù)在獨立的線程中異步執(zhí)行。
首先需要在配置類中啟用異步支持,并配置一個線程池,然后在每個定時任務(wù)方法上添加@Async注解。
@EnableAsync @Configuration public class AsyncConfig { @Bean public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); executor.setCorePoolSize(10); executor.setMaxPoolSize(20); executor.setQueueCapacity(200); executor.setThreadNamePrefix("Async-"); executor.initialize(); return executor; } }
測試代碼:
@Async @Scheduled(cron = "*/1 * * * * *") public void a() throws InterruptedException { log.info("A Start {}!", System.currentTimeMillis()); Thread.sleep(2000); log.info("A End {}!", System.currentTimeMillis()); } @Async @Scheduled(cron = "*/1 * * * * *") public void b() { log.info("B Start {}!", System.currentTimeMillis()); log.info("B End {}!", System.currentTimeMillis()); }
部分測試結(jié)果:
15:26:52.008 [Async-2] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967612008! 15:26:52.008 [Async-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967612008! 15:26:52.009 [Async-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967612009! 15:26:53.002 [Async-4] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967613002! 15:26:53.002 [Async-3] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967613002! 15:26:53.002 [Async-3] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967613002! 15:26:54.001 [Async-6] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967614001! 15:26:54.001 [Async-5] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967614001! 15:26:54.001 [Async-5] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967614001! 15:26:54.010 [Async-2] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716967614010! 15:26:55.002 [Async-8] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967615002! 15:26:55.002 [Async-7] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967615002! 15:26:55.002 [Async-7] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967615002! 15:26:55.002 [Async-4] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716967615002! 15:26:56.001 [Async-10] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967616001! 15:26:56.001 [Async-9] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967616001! 15:26:56.001 [Async-9] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967616001! 15:26:56.002 [Async-6] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716967616002! 15:26:57.001 [Async-3] INFO c.x.e.m.SchedulerTask - [a,44] - A Start 1716967617001! 15:26:57.001 [Async-1] INFO c.x.e.m.SchedulerTask - [b,52] - B Start 1716967617001! 15:26:57.001 [Async-1] INFO c.x.e.m.SchedulerTask - [b,53] - B End 1716967617001! 15:26:57.002 [Async-8] INFO c.x.e.m.SchedulerTask - [a,46] - A End 1716967617002!
測試結(jié)果分析:
- A和B是并行的;
- A和A或者B和B也是并行的。
3.總結(jié)
到此這篇關(guān)于SpringBoot使用@Scheduled實現(xiàn)定時任務(wù)的并行執(zhí)行的文章就介紹到這了,更多相關(guān)SpringBoot @Scheduled任務(wù)并行執(zhí)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring @Async無法實現(xiàn)異步的解決方案
這篇文章主要介紹了Spring @Async無法實現(xiàn)異步的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序詳解
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之希爾排序,結(jié)合實例形式分析了希爾排序的概念、原理、實現(xiàn)方法與相關(guān)注意事項,需要的朋友可以參考下2017-05-05java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實例詳解
這篇文章主要介紹了java 中模擬UDP傳輸?shù)陌l(fā)送端和接收端實例詳解的相關(guān)資料,需要的朋友可以參考下2017-03-03詳解用Kotlin寫一個基于Spring Boot的RESTful服務(wù)
這篇文章主要介紹了詳解用Kotlin寫一個基于Spring Boot的RESTful服務(wù) ,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05簡單了解Thymeleaf語法 數(shù)據(jù)延遲加載使用實例
這篇文章主要介紹了簡單了解Thymeleaf語法 數(shù)據(jù)延遲加載使用實例,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2010-05-05springboot2.0以上調(diào)度器配置線程池的實現(xiàn)
這篇文章主要介紹了springboot2.0以上調(diào)度器配置線程池的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-12-12