SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑
要注意什么坑
不繞彎子了,直接說這個坑是啥:
SpringBoot使用@scheduled定時執(zhí)行任務(wù)的時候是在一個單線程中,如果有多個任務(wù),其中一個任務(wù)執(zhí)行時間過長,則有可能會導(dǎo)致其他后續(xù)任務(wù)被阻塞直到該任務(wù)執(zhí)行完成。也就是會造成一些任務(wù)無法定時執(zhí)行的錯覺
可以通過如下代碼進(jìn)行測試:
? ? @Scheduled(cron = "0/1 * * * * ? ") ? ? public void deleteFile() throws InterruptedException { ? ? ? ? log.info("111delete success, time:" + new Date().toString()); ? ? ? ? Thread.sleep(1000 * 5);//模擬長時間執(zhí)行,比如IO操作,http請求 ? ? } ? ? @Scheduled(cron = "0/1 * * * * ? ") ? ? public void syncFile() { ? ? ? ? log.info("222sync success, time:" + new Date().toString()); ? ? } ? ?? /**輸出如下: [pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:13 CST 2018 [pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:18 CST 2018 [pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:19 CST 2018 [pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:24 CST 2018 [pool-1-thread-1] : 222sync success, time:Mon Nov 26 20:42:25 CST 2018 [pool-1-thread-1] : 111delete success, time:Mon Nov 26 20:42:25 CST 2018 上面的日志中可以明顯的看到syncFile被阻塞了,直達(dá)deleteFile執(zhí)行完它才執(zhí)行了 而且從日志信息中也可以看出@Scheduled是使用了一個線程池中的一個單線程來執(zhí)行所有任務(wù)的。 **/ /**如果把Thread.sleep(1000*5)注釋了,輸出如下: [pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:04 CST 2018 [pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:04 CST 2018 [pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:05 CST 2018 [pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:05 CST 2018 [pool-1-thread-1]: 111delete success, time:Mon Nov 26 20:48:06 CST 2018 [pool-1-thread-1]: 222sync success, time:Mon Nov 26 20:48:06 CST 2018 這下正常了 **/
解決辦法
1.將@Scheduled注釋的方法內(nèi)部改成異步執(zhí)行
如下:
//當(dāng)然了,構(gòu)建一個合理的線程池也是一個關(guān)鍵,否則提交的任務(wù)也會在自己構(gòu)建的線程池中阻塞 ? ? ExecutorService service = Executors.newFixedThreadPool(5); ? ? @Scheduled(cron = "0/1 * * * * ? ") ? ? public void deleteFile() { ? ? ? ? service.execute(() -> { ? ? ? ? ? ? log.info("111delete success, time:" + new Date().toString()); ? ? ? ? ? ? try { ? ? ? ? ? ? ? ? Thread.sleep(1000 * 5);//改成異步執(zhí)行后,就算你再耗時也不會印象到后續(xù)任務(wù)的定時調(diào)度了 ? ? ? ? ? ? } catch (InterruptedException e) { ? ? ? ? ? ? ? ? e.printStackTrace(); ? ? ? ? ? ? } ? ? ? ? }); ? ? } ? ? @Scheduled(cron = "0/1 * * * * ? ") ? ? public void syncFile() { ? ? ? ? service.execute(()->{ ? ? ? ? ? ? log.info("222sync success, time:" + new Date().toString()); ? ? ? ? }); ? ? }
2.把Scheduled配置成成多線程執(zhí)行
@Configuration public class ScheduleConfig implements SchedulingConfigurer { ? ? @Override ? ? public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ? ? ? ? //當(dāng)然了,這里設(shè)置的線程池是corePoolSize也是很關(guān)鍵了,自己根據(jù)業(yè)務(wù)需求設(shè)定 ? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5)); ? ? ? ?? ? ? ? ?? ? ? ? ? /**為什么這么說呢? ? ? ? ? 假設(shè)你有4個任務(wù)需要每隔1秒執(zhí)行,而其中三個都是比較耗時的操作可能需要10多秒,而你上面的語句是這樣寫的: ? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3)); ? ? ? ? 那么仍然可能導(dǎo)致最后一個任務(wù)被阻塞不能定時執(zhí)行 ? ? ? ? **/ ? ? } }
到此這篇關(guān)于SpringBoot中使用@scheduled定時執(zhí)行任務(wù)的坑的文章就介紹到這了,更多相關(guān)SpringBoot @scheduled定時執(zhí)行內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值
這篇文章主要介紹了SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-11-11springBoot中的CORS跨域注解@CrossOrigin詳解
這篇文章主要介紹了springBoot中的CORS跨域注解@CrossOrigin詳解,通常,服務(wù)于?JS?的主機(jī)(例如?example.com)與服務(wù)于數(shù)據(jù)的主機(jī)(例如?api.example.com)是不同的,在這種情況下,CORS?可以實(shí)現(xiàn)跨域通信,需要的朋友可以參考下2023-12-12總結(jié)Java常用加解密方法AES?SHA1?md5
這篇文章主要為大家介紹了Java常用加密方法AES?SHA1?md5總結(jié)及示例demo,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化
本篇文章主要介紹了詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化,具有一定的參考價值,有興趣的可以了解一下2017-09-098個簡單部分開啟Java語言學(xué)習(xí)之路 附j(luò)ava學(xué)習(xí)書單
8個簡單部分開啟Java語言學(xué)習(xí)之路,附j(luò)ava學(xué)習(xí)書單,這篇文章主要向大家介紹了學(xué)習(xí)java語言的方向,感興趣的小伙伴們可以參考一下2016-09-09如何解決 Java 中的 IndexOutOfBoundsException 異
當(dāng)我們在 Java 中使用 List 的時候,有時候會出現(xiàn)向 List 中不存在的位置設(shè)置新元素的情況,從而導(dǎo)致 IndexOutOfBoundsException 異常,本文將會介紹這個問題的產(chǎn)生原因以及解決方案2023-10-10Spring中的@ConfigurationProperties詳解
這篇文章主要介紹了Spring中的@ConfigurationProperties詳解,ConfigurationProperties注解主要用于將外部配置文件配置的屬性填充到這個Spring Bean實(shí)例中,需要的朋友可以參考下2023-09-09Spring Cache優(yōu)化數(shù)據(jù)庫訪問的項(xiàng)目實(shí)踐
本文主要介紹了Spring Cache優(yōu)化數(shù)據(jù)庫訪問的項(xiàng)目實(shí)踐,將創(chuàng)建一個簡單的圖書管理應(yīng)用作為示例,并演示如何通過緩存減少對數(shù)據(jù)庫的頻繁查詢,感興趣的可以了解一下2024-01-01