要注意什么坑
不繞彎子了,直接說這個坑是啥:
SpringBoot使用@scheduled定時執行任務的時候是在一個單線程中,如果有多個任務,其中一個任務執行時間過長,則有可能會導致其他后續任務被阻塞直到該任務執行完成。也就是會造成一些任務無法定時執行的錯覺
可以通過如下代碼進行測試:
@Scheduled(cron = "0/1 * * * * ? ") public void deleteFile() throws InterruptedException { log.info("111delete success, time:" + new Date().toString()); Thread.sleep(1000 * 5);//模擬長時間執行,比如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執行完它才執行了 而且從日志信息中也可以看出@Scheduled是使用了一個線程池中的一個單線程來執行所有任務的。 **/ /**如果把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注釋的方法內部改成異步執行
如下:
//當然了,構建一個合理的線程池也是一個關鍵,否則提交的任務也會在自己構建的線程池中阻塞 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);//改成異步執行后,就算你再耗時也不會印象到后續任務的定時調度了 } catch (InterruptedException e) { e.printStackTrace(); } }); } @Scheduled(cron = "0/1 * * * * ? ") public void syncFile() { service.execute(()->{ log.info("222sync success, time:" + new Date().toString()); }); }
2.把Scheduled配置成成多線程執行
@Configuration public class ScheduleConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //當然了,這里設置的線程池是corePoolSize也是很關鍵了,自己根據業務需求設定 taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5)); /**為什么這么說呢? 假設你有4個任務需要每隔1秒執行,而其中三個都是比較耗時的操作可能需要10多秒,而你上面的語句是這樣寫的: taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3)); 那么仍然可能導致最后一個任務被阻塞不能定時執行 **/ } }
添加@EnableScheduling注解到入口類聲明上面或配置類上。
————————————————
版權聲明:本文為CSDN博主「一個行走的民」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/zhaominpro/article/details/84561966