@Scheduled定時器使用注意事項及說明
@Scheduled定時器使用注意事項
首先定時器可以固定執(zhí)行時間使用cron表達式,也可以控制方法執(zhí)行的間隔時間fixedDelay,這里使用的是cron,創(chuàng)建了schedule包,將定時任務(wù)放在了schedule包下,下面開始進入正題。
一般在程序中直接使用定時器,但是最好設(shè)置一下JVM的默認(rèn)時區(qū),因為JVM默認(rèn)時區(qū)可能和本機時區(qū)不一樣,不同操作系統(tǒng)默認(rèn)時區(qū)可能不一樣。
使用靜態(tài)變量static聲明的靜態(tài)變量具有全局作用域,對全局造成影響,保證系統(tǒng)整個時區(qū)一致
如果只想針對某部分設(shè)置時區(qū)需要顯示指定時區(qū),不影響全局結(jié)果
package com.test.hello.task; import com.test.hello.service.TestEntityService; import com.test.hello.service.TestOneEntityService; import com.test.hello.service.TestTwoEntityService; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.format.DateTimeFormatter; import java.util.TimeZone; @Slf4j @Component public class TestTask { //全局修改時區(qū),設(shè)置JVM的默認(rèn)時區(qū),影響整個 Java 虛擬機中所有涉及日期和時間的操作所使用的時區(qū)。 //在Java中,通過 TimeZone.setDefault() 方法可以實現(xiàn)對 JVM 默認(rèn)時區(qū)的修改。 static { TimeZone.setDefault(TimeZone.getTimeZone("GMT+8")); } //顯示指定時區(qū),不影響全局 // 顯式指定使用的時區(qū)為 GMT+8 ZoneId zoneId = ZoneId.of("GMT+8"); // 獲取當(dāng)前時間 LocalDateTime currentTime = LocalDateTime.now(zoneId); // 格式化日期時間 DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); String formattedTime = currentTime.format(formatter); @Autowired private TestEntityService testEntityService; @Autowired private TestOneEntityService testOneEntityService; @Autowired private TestTwoEntityService testTwoEntityService; /** * 每天的00:00:00執(zhí)行任務(wù) */ @Scheduled(cron = "0 0 0 * * *") public void scheduled() { log.info("=====>>>>>使用cron {}", testEntityService.countSum()); } @Scheduled(cron = "0 0/1 * * * ?") public void scheduledStatisticsOnAboardNum() { log.info("=====>>>>>統(tǒng)計: 使用cron {}", testEntityService.countSum()); log.info("=====>>>>>)統(tǒng)計: 使用cron {}", testOneEntityService.countSum()); log.info("=====>>>>>合計統(tǒng)計: 使用cron {}", testTwoEntityService.countSum()); } }
為了美觀性,每個定時都單獨放在一個類,類目以功能+Schedule結(jié)尾,該類加上@Component表示交給spring管理,定時器的表達式可以在nacos中聲明,防止后期需要改定時任務(wù)的時候頻繁修改代碼,只需要修改nacos配置文件即可(nacos配置文件中聲明定時器名字的時候不得以特殊字符開頭,不然會報錯踩坑)
package com.test.stats.schedule; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component @Slf4j public class TestSchedule { //定時器表達式配置在nacos中 @Scheduled(cron = "${testSchedule.oneCron}") //單獨配置線程池 @Async("PoolThread") public void testScheduled() { //定時器執(zhí)行的邏輯代碼 } }
以上代碼使用到了 @Async異步注解,這里我使用了一個線程池,可以根據(jù)自己的業(yè)務(wù)需求自行決定。
定義線程池的意義在與所有執(zhí)行定時器都是副線程執(zhí)行,不影響主線程。
使用線程池的情況
- 異步執(zhí)行任務(wù): 任務(wù)在后臺異步執(zhí)行,不阻塞當(dāng)前線程或應(yīng)用程序的其他部分時,使用線程池。例如,處理異步消息、發(fā)送電子郵件、執(zhí)行后臺計算等。
- 提高并發(fā)性: 程序需要同時處理多個并發(fā)任務(wù)時,線程池可以有效地管理和分配系統(tǒng)資源,提高系統(tǒng)的并發(fā)性和性能。這對于處理大量獨立的任務(wù)或請求非常有用。
- 避免線程創(chuàng)建和銷毀的開銷: 線程的創(chuàng)建和銷毀通常會帶來較大的開銷。通過使用線程池,可以避免頻繁地創(chuàng)建和銷毀線程,而是重用現(xiàn)有線程,減少資源開銷。
- 限制資源使用: 使用線程池可以限制同時執(zhí)行的任務(wù)數(shù)量,以控制系統(tǒng)資源的使用。這對于避免系統(tǒng)過度負(fù)載或資源耗盡非常重要。
- 任務(wù)隊列管理: 線程池通常具有任務(wù)隊列,可以將需要執(zhí)行的任務(wù)添加到隊列中。這使得任務(wù)按照預(yù)定的順序執(zhí)行,而無需手動管理線程的執(zhí)行。
總結(jié):
如果定時器執(zhí)行的比較頻繁,不想每次都new線程,而且內(nèi)次都從線程池里取線程,用完線程池自己根據(jù)GC回收機制銷毀,可以考慮編寫線程池
線程池代碼
package com.test.hello.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import java.util.concurrent.ThreadPoolExecutor; @Configuration public class ThreadPoolTaskConfig { //這里的命名可以在報錯的時候清楚是哪個線程報錯了 @Bean("PoolThread") public ThreadPoolTaskExecutor threadPoolWorkTaskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //線程池創(chuàng)建的核心線程數(shù),線程池維護線程的最少數(shù)量,即使沒有任務(wù)需要執(zhí)行,也會一直存活 executor.setCorePoolSize(8); //如果設(shè)置allowCoreThreadTimeout=true(默認(rèn)false)時,核心線程會超時關(guān)閉 //executor.setAllowCoreThreadTimeOut(true); //阻塞隊列 當(dāng)核心線程數(shù)達到最大時,新任務(wù)會放在隊列中排隊等待執(zhí)行 executor.setQueueCapacity(124); //最大線程池數(shù)量,當(dāng)線程數(shù)>=corePoolSize,且任務(wù)隊列已滿時。線程池會創(chuàng)建新線程來處理任 //任務(wù)隊列已滿時, 且當(dāng)線程數(shù)=maxPoolSize,,線程池會拒絕處理任務(wù)而拋出異常 executor.setMaxPoolSize(64); //當(dāng)線程空閑時間達到keepAliveTime時,線程會退出,直到線程數(shù)量=corePoolSize //允許線程空閑時間30秒,當(dāng)maxPoolSize的線程在空閑時間到達的時候銷毀 //如果allowCoreThreadTimeout=true,則會直到線程數(shù)量=0 executor.setKeepAliveSeconds(30); //spring 提供的 ThreadPoolTaskExecutor 線程池,是有setThreadNamePrefix() 方法的。 //jdk 提供的ThreadPoolExecutor 線程池是沒有 setThreadNamePrefix() 方法的 executor.setThreadNamePrefix("PoolThread"); // rejection-policy:拒絕策略:當(dāng)線程數(shù)已經(jīng)達到maxSize的時候,如何處理新任務(wù) // CallerRunsPolicy():交由調(diào)用方線程運行,比如 main 線程;如果添加到線程池失敗,那么主線程會自己去執(zhí)行該任務(wù),不會等待線程池中的線程去執(zhí)行 // AbortPolicy():該策略是線程池的默認(rèn)策略,如果線程池隊列滿了丟掉這個任務(wù)并且拋出RejectedExecutionException異常。 // DiscardPolicy():如果線程池隊列滿了,會直接丟掉這個任務(wù)并且不會有任何異常 // DiscardOldestPolicy():丟棄隊列中最老的任務(wù),隊列滿了,會將最早進入隊列的任務(wù)刪掉騰出空間,再嘗試加入隊列 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy()); executor.initialize(); return executor; } }
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Spring+quartz實現(xiàn)定時發(fā)送郵件功能實例
spring提供的定時發(fā)送郵件功能一直深受廣大web開發(fā)者的喜愛,這篇文章主要介紹了Spring+quartz實現(xiàn)定時發(fā)送郵件功能實例,有興趣的可以了解一下。2017-03-03JAVA中String類與StringBuffer類的區(qū)別
這篇文章主要為大家詳細(xì)介紹了JAVA中String類與StringBuffer類的區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-12-12java實現(xiàn)XML與JSON轉(zhuǎn)換的便捷實用方法
這篇文章主要為大家介紹了java實現(xiàn)XML與JSON轉(zhuǎn)換的便捷實用方法,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-12-12單一職責(zé)原則_動力節(jié)點Java學(xué)院整理
這篇文章主要為大家詳細(xì)介紹了單一職責(zé)原則的相關(guān)資料,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-08-08Java基礎(chǔ)之反射技術(shù)相關(guān)知識總結(jié)
今天帶大家復(fù)習(xí)Java基礎(chǔ)知識,文中對Java反射技術(shù)介紹的非常詳細(xì),對正在學(xué)習(xí)Java的小伙伴們很有幫助,,需要的朋友可以參考下2021-05-05使用Idea簡單快速搭建springcloud項目的圖文教程
這篇文章主要介紹了使用Idea簡單快速搭建springcloud項目,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-01-01Springboot自動配置與@Configuration配置類詳解
這篇文章主要介紹了SpringBoot中的@Configuration與自動配置,在進行項目編寫前,我們還需要知道一個東西,就是SpringBoot對我們的SpringMVC還做了哪些配置,包括如何擴展,如何定制,只有把這些都搞清楚了,我們在之后使用才會更加得心應(yīng)手2022-07-07