解決定時(shí)任務(wù)@Scheduled沒有準(zhǔn)時(shí)執(zhí)行的原因及分析
定時(shí)任務(wù)@Scheduled沒有準(zhǔn)時(shí)執(zhí)行的原因
項(xiàng)目中用到了定時(shí)任務(wù)往前端推送數(shù)據(jù),間隔2秒 @Scheduled(cron = "0/2 * * * * ? "),測(cè)試發(fā)現(xiàn),每次任務(wù)執(zhí)行并不是2秒,而是1-5秒之間。
執(zhí)行時(shí)間:::::Wed Nov 30 16:20:19 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:20:20 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:20:24 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:20:29 CST 2022
原因
了解發(fā)現(xiàn),如果程序中沒有指定線程池的配置,也就是Spring的Scheduled的默認(rèn)線程池配置,其線程池的線程數(shù)默認(rèn)為1,也就是說默認(rèn)情況下,Spring用來處理定時(shí)任務(wù)的線程只有一個(gè)。
如果有定時(shí)的處理時(shí)間占用時(shí)間比較長,那么就會(huì)導(dǎo)致下一個(gè)定時(shí)任務(wù),即使到達(dá)了配置的定時(shí)時(shí)間,也不會(huì)立即執(zhí)行,而是等到前面一個(gè)任務(wù)處理完成了,才會(huì)進(jìn)行處理。
而項(xiàng)目中還有數(shù)個(gè)定時(shí)任務(wù)。
解決法案
是初始一個(gè)定時(shí)任務(wù)執(zhí)行線程池
@Configuration public class ScheduleConfig implements SchedulingConfigurer { ? ? ? @Override ? ? public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { ? ? ? ? Method[] methods = BatchProperties.Job.class.getMethods(); ? ? ? ? int defaultPoolSize = 10; ? ? ? ? int corePoolSize = 0; ? ? ? ? if (methods != null && methods.length > 0) { ? ? ? ? ? ? for (Method method : methods) { ? ? ? ? ? ? ? ? Scheduled annotation = method.getAnnotation(Scheduled.class); ? ? ? ? ? ? ? ? if (annotation != null) { ? ? ? ? ? ? ? ? ? ? corePoolSize++; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } ? ? ? ? ? ? if (defaultPoolSize > corePoolSize) ? ? ? ? ? ? ? ? corePoolSize = defaultPoolSize; ? ? ? ? } ? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize)); ? ? ? } }
再次測(cè)試,跟設(shè)置的間隔時(shí)間2秒一致。
執(zhí)行時(shí)間:::::Wed Nov 30 16:48:32 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:48:34 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:48:36 CST 2022
執(zhí)行時(shí)間:::::Wed Nov 30 16:48:38 CST 2022
定時(shí)任務(wù)@Scheduled入門
一個(gè)最簡單的例子
啟動(dòng)類添加注解
@EnableScheduling // 開啟定時(shí)任務(wù)
編寫單線程demo
cron 表達(dá)式
/** * cron 表達(dá)式 * 每2秒執(zhí)行一次 * @throws InterruptedException */ @Scheduled(cron = "0/2 * * * * *") public void test() throws InterruptedException { // 經(jīng)過測(cè)試,使用cron表達(dá)式,定時(shí)任務(wù)第二次會(huì)等待第一次執(zhí)行完畢再開始! Thread.sleep(5000L); log.info("定時(shí)任務(wù)測(cè)試cron:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); }
fixedDelay
/** * fixedDelay: * 第一次執(zhí)行完畢才會(huì)執(zhí)行第二次,時(shí)間間隔變?yōu)榱?秒 * @throws InterruptedException */ @Scheduled(fixedDelay = 2000L) public void test2() throws InterruptedException { Thread.sleep(5000L); log.info("定時(shí)任務(wù)測(cè)試fixedDelay:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); }
fixedRate
/** * fixedRate: * 每隔2秒就會(huì)執(zhí)行, 但是因?yàn)閱尉€程,所以在5秒后會(huì)輸出,間隔就是5秒 * @throws InterruptedException */ @Scheduled(fixedRate = 2000L) public void test3() throws InterruptedException { Thread.sleep(5000L); log.info("定時(shí)任務(wù)測(cè)試fixedRate:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date())); }
如果是一起執(zhí)行這三個(gè)定時(shí)任務(wù),那么會(huì)一個(gè)一個(gè)的來, 因?yàn)橹挥幸粋€(gè)線程.
多線程
/** * * @author GMaya */ @Configuration @EnableAsync public class ScheduleConfig { @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(50); // 設(shè)置線程池大小 return taskScheduler; } }
如果只是加這一個(gè)配置類, 確實(shí)是使用了多線程, 每個(gè)定時(shí)任務(wù)都互相不影響.
但是一個(gè)線程第一次阻塞了,第二次就不行了,所以在定時(shí)任務(wù)上再加
@Async
就是說你這次失敗了, 不要影響我下次的運(yùn)行
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java springmvc 注冊(cè)中央調(diào)度器代碼解析
這篇文章主要介紹了java springmvc 注冊(cè)中央調(diào)度器代碼解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08MybatisPlus使用@TableLogic實(shí)現(xiàn)邏輯刪除過程
這篇文章主要介紹了MybatisPlus使用@TableLogic實(shí)現(xiàn)邏輯刪除過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05Java多線程中關(guān)于join方法的使用實(shí)例解析
本文通過實(shí)例代碼給大家實(shí)例介紹了Java多線程中關(guān)于join方法的使用,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友參考下2017-01-01淺析JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承
這篇文章主要介紹了 JAVA中的內(nèi)存結(jié)構(gòu)、重載、this與繼承的相關(guān)資料,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03@RequestParam 接收參數(shù)的值為null的處理方式
這篇文章主要介紹了@RequestParam 接收參數(shù)的值為null的處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11IntelliJ IDEA像Eclipse一樣打開多個(gè)項(xiàng)目的圖文教程
這篇文章主要介紹了IntelliJ IDEA像Eclipse一樣打開多個(gè)項(xiàng)目的方法圖文教程講解,需要的朋友可以參考下2018-03-03Java如何向Word模板中插入Base64圖片和數(shù)據(jù)信息
這篇文章主要介紹了Java如何向Word模板中插入Base64圖片和數(shù)據(jù)信息問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-07-07java的各種集合為什么不安全(List、Set、Map)以及代替方案
這篇文章主要介紹了java的各種集合為什么不安全(List、Set、Map)以及代替方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Java編程文件遍歷之指定遍歷的層數(shù)詳細(xì)代碼
這篇文章主要介紹了Java編程文件遍歷之指定遍歷的層數(shù)詳細(xì)代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-12-12CountDownLatch源碼解析之a(chǎn)wait()
這篇文章主要為大家詳細(xì)解析了CountDownLatch源碼之a(chǎn)wait方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-04-04