SpringBoot中使用@scheduled定時(shí)執(zhí)行任務(wù)的坑
要注意什么坑
不繞彎子了,直接說(shuō)這個(gè)坑是啥:
SpringBoot使用@scheduled定時(shí)執(zhí)行任務(wù)的時(shí)候是在一個(gè)單線程中,如果有多個(gè)任務(wù),其中一個(gè)任務(wù)執(zhí)行時(shí)間過(guò)長(zhǎng),則有可能會(huì)導(dǎo)致其他后續(xù)任務(wù)被阻塞直到該任務(wù)執(zhí)行完成。也就是會(huì)造成一些任務(wù)無(wú)法定時(shí)執(zhí)行的錯(cuò)覺(jué)
可以通過(guò)如下代碼進(jìn)行測(cè)試:
? ? @Scheduled(cron = "0/1 * * * * ? ")
? ? public void deleteFile() throws InterruptedException {
? ? ? ? log.info("111delete success, time:" + new Date().toString());
? ? ? ? Thread.sleep(1000 * 5);//模擬長(zhǎng)時(shí)間執(zhí)行,比如IO操作,http請(qǐng)求
? ? }
? ? @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是使用了一個(gè)線程池中的一個(gè)單線程來(lái)執(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)建一個(gè)合理的線程池也是一個(gè)關(guān)鍵,否則提交的任務(wù)也會(huì)在自己構(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í)行后,就算你再耗時(shí)也不會(huì)印象到后續(xù)任務(wù)的定時(shí)調(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));
? ? ? ??
? ? ? ??
? ? ? ? /**為什么這么說(shuō)呢?
? ? ? ? 假設(shè)你有4個(gè)任務(wù)需要每隔1秒執(zhí)行,而其中三個(gè)都是比較耗時(shí)的操作可能需要10多秒,而你上面的語(yǔ)句是這樣寫的:
? ? ? ? taskRegistrar.setScheduler(Executors.newScheduledThreadPool(3));
? ? ? ? 那么仍然可能導(dǎo)致最后一個(gè)任務(wù)被阻塞不能定時(shí)執(zhí)行
? ? ? ? **/
? ? }
}到此這篇關(guān)于SpringBoot中使用@scheduled定時(shí)執(zhí)行任務(wù)的坑的文章就介紹到這了,更多相關(guān)SpringBoot @scheduled定時(shí)執(zhí)行內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- SpringBoot中定時(shí)任務(wù)@Scheduled的多線程使用詳解
- SpringBoot通過(guò)@Scheduled實(shí)現(xiàn)定時(shí)任務(wù)及單線程運(yùn)行問(wèn)題解決
- SpringBoot?ScheduledTaskRegistrar解決動(dòng)態(tài)定時(shí)任務(wù)思路詳解
- SpringBoot定時(shí)任務(wù)動(dòng)態(tài)擴(kuò)展ScheduledTaskRegistrar詳解
- SpringBoot中定時(shí)任務(wù)@Scheduled注解的使用解讀
- 解決SpringBoot中的Scheduled單線程執(zhí)行問(wèn)題
- springboot使用定時(shí)器@Scheduled不管用的解決
- 帶你3分鐘帶你搞定Spring Boot中Schedule
相關(guān)文章
Spring框架實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼功能的代碼示例
之前項(xiàng)目需要在驗(yàn)證碼模塊,增加滑動(dòng)驗(yàn)證碼,用來(lái)給手機(jī)端使用的,大概看了下,主要方法就是將圖片切割,然后記住偏移量,進(jìn)行滑動(dòng),所以本文給大家介紹了Spring框架實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼功能的方法示例,需要的朋友可以參考下2024-07-07
Java語(yǔ)言實(shí)現(xiàn)Blowfish加密算法完整代碼分享
這篇文章主要介紹了Java語(yǔ)言實(shí)現(xiàn)Blowfish加密算法完整代碼分享,簡(jiǎn)單介紹了blowfish加密算法,具有一定借鑒價(jià)值,需要的朋友可以參考下。2017-11-11
Java實(shí)體類(entity)作用說(shuō)明
這篇文章主要介紹了Java實(shí)體類(entity)作用說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08
mybatis中BigDecimal中的0存為null的坑及解決
在使用MyBatis進(jìn)行數(shù)據(jù)庫(kù)操作時(shí),若Java中屬性類型為BigDecimal且值為0,插入數(shù)據(jù)庫(kù)時(shí)可能會(huì)變?yōu)閚ull,而不是0,這個(gè)問(wèn)題可能是由于MyBatis在處理BigDecimal類型時(shí)的弱類型判斷導(dǎo)致的,當(dāng)BigDecimal變量與空字符串進(jìn)行比較時(shí),MyBatis可能將其視為null2024-10-10
Spring Boot MyBatis 連接數(shù)據(jù)庫(kù)配置示例
本篇文章主要介紹了Spring Boot MyBatis 連接數(shù)據(jù)庫(kù)示例的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-02-02
Java集合中的fail-fast(快速失敗)機(jī)制詳解
這篇文章主要給大家介紹了關(guān)于Java集合中fail-fast(快速失敗)機(jī)制的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-02-02
spring boot + mybatis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的讀寫分離
這篇文章主要給大家介紹了關(guān)于spring boot + mybatis如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的讀寫分離的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用spring boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09
Java之ThreadLocal使用常見(jiàn)和方式案例講解
這篇文章主要介紹了Java之ThreadLocal使用常見(jiàn)和方式案例講解,本篇文章通過(guò)簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08

