SpringBoot中使用@scheduled定時執(zhí)行任務的坑
要注意什么坑
不繞彎子了,直接說這個坑是啥:
SpringBoot使用@scheduled定時執(zhí)行任務的時候是在一個單線程中,如果有多個任務,其中一個任務執(zhí)行時間過長,則有可能會導致其他后續(xù)任務被阻塞直到該任務執(zhí)行完成。也就是會造成一些任務無法定時執(zhí)行的錯覺
可以通過如下代碼進行測試:
? ? @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被阻塞了,直達deleteFile執(zhí)行完它才執(zhí)行了 而且從日志信息中也可以看出@Scheduled是使用了一個線程池中的一個單線程來執(zhí)行所有任務的。 **/ /**如果把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注釋的方法內部改成異步執(zhí)行
如下:
//當然了,構建一個合理的線程池也是一個關鍵,否則提交的任務也會在自己構建的線程池中阻塞 ? ? 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ù)任務的定時調度了 ? ? ? ? ? ? } 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) { ? ? ? ? //當然了,這里設置的線程池是corePoolSize也是很關鍵了,自己根據業(yè)務需求設定 ? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5)); ? ? ? ?? ? ? ? ?? ? ? ? ? /**為什么這么說呢? ? ? ? ? 假設你有4個任務需要每隔1秒執(zhí)行,而其中三個都是比較耗時的操作可能需要10多秒,而你上面的語句是這樣寫的: ? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3)); ? ? ? ? 那么仍然可能導致最后一個任務被阻塞不能定時執(zhí)行 ? ? ? ? **/ ? ? } }
到此這篇關于SpringBoot中使用@scheduled定時執(zhí)行任務的坑的文章就介紹到這了,更多相關SpringBoot @scheduled定時執(zhí)行內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值
這篇文章主要介紹了SpringBoot 使用 @Value 注解讀取配置文件給靜態(tài)變量賦值,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11springBoot中的CORS跨域注解@CrossOrigin詳解
這篇文章主要介紹了springBoot中的CORS跨域注解@CrossOrigin詳解,通常,服務于?JS?的主機(例如?example.com)與服務于數據的主機(例如?api.example.com)是不同的,在這種情況下,CORS?可以實現跨域通信,需要的朋友可以參考下2023-12-12詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化
本篇文章主要介紹了詳解SpringBoot初始教程之Tomcat、Https配置以及Jetty優(yōu)化,具有一定的參考價值,有興趣的可以了解一下2017-09-09如何解決 Java 中的 IndexOutOfBoundsException 異
當我們在 Java 中使用 List 的時候,有時候會出現向 List 中不存在的位置設置新元素的情況,從而導致 IndexOutOfBoundsException 異常,本文將會介紹這個問題的產生原因以及解決方案2023-10-10Spring中的@ConfigurationProperties詳解
這篇文章主要介紹了Spring中的@ConfigurationProperties詳解,ConfigurationProperties注解主要用于將外部配置文件配置的屬性填充到這個Spring Bean實例中,需要的朋友可以參考下2023-09-09