Spring內(nèi)置定時(shí)任務(wù)調(diào)度@Scheduled使用詳解
Spring提供了@Scheduled注解用于定時(shí)任務(wù)。
一、@Scheduled的基本使用
啟用調(diào)度支持:@EnableScheduling
可以將@Scheduled注釋與觸發(fā)器元數(shù)據(jù)一起添加到方法中。例如,以下方法每隔5秒調(diào)用一次,并具有固定的延遲,這意味著周期是從前面每次調(diào)用的完成時(shí)間開始計(jì)算的
@Scheduled(fixedDelay=5000)
public void doSomething() {
// something that should execute periodically
}
如果需要固定速率執(zhí)行,可以更改批注中指定的屬性名。以下方法每5秒調(diào)用一次(在每次調(diào)用的連續(xù)開始時(shí)間之間計(jì)算)
@Scheduled(fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
對于固定延遲和固定速率任務(wù),可以通過指示在首次執(zhí)行方法之前要等待的毫秒數(shù)來指定初始延遲
@Scheduled(initialDelay=1000, fixedRate=5000)
public void doSomething() {
// something that should execute periodically
}
如果簡單的周期性調(diào)度不夠表達(dá),可以提供cron表達(dá)式。例如,以下命令僅在工作日執(zhí)行:
@Scheduled(cron="*/5 * * * * MON-FRI")
public void doSomething() {
// something that should execute on weekdays only
}
實(shí)現(xiàn)SchedulingConfigurer接口,重寫configureTasks方法:
@Schedule注解的一個(gè)缺點(diǎn)就是其定時(shí)時(shí)間不能動(dòng)態(tài)更改,它適用于具有固定任務(wù)周期的任務(wù),若要修改任務(wù)執(zhí)行周期,只能走“停服務(wù)→修改任務(wù)執(zhí)行周期→重啟服務(wù)”這條路。而基于 SchedulingConfigurer 接口方式可以做到。SchedulingConfigurer 接口可以實(shí)現(xiàn)在@Configuration等注解類上。
ScheduledTaskRegistrar類包括以下幾個(gè)重要方法:
void addTriggerTask(Runnable task, Trigger trigger)
void addTriggerTask(TriggerTask task)
void addCronTask(Runnable task, String expression)
void addCronTask(CronTask task)
void addFixedRateTask(Runnable task, long interval)
void addFixedRateTask(IntervalTask task)
void addFixedDelayTask(Runnable task, long delay)
void addFixedDelayTask(IntervalTask task)
具體實(shí)現(xiàn)參考如下:
@Component
public class TestTask implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(new Runnable() {
@Override
public void run() {
// 定時(shí)任務(wù)要執(zhí)行的內(nèi)容
System.out.println("【開始執(zhí)行定時(shí)任務(wù)。。?!?);
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// 定時(shí)任務(wù)觸發(fā),可修改定時(shí)任務(wù)的執(zhí)行周期
String cron = "0 0/5 * * * ?"; //可以將表達(dá)式配置在數(shù)據(jù)庫中
CronTrigger trigger = new CronTrigger(cron);
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return nextExecDate;
}
});
}
}
提示:如果在數(shù)據(jù)庫修改時(shí)格式出現(xiàn)錯(cuò)誤,則定時(shí)任務(wù)會(huì)停止,即使重新修改正確;此時(shí)只能重新啟動(dòng)項(xiàng)目才能恢復(fù)。
二、使用@Scheduled注意事項(xiàng)
- spring的注解@Scheduled 需要寫在實(shí)現(xiàn)方法上;
- 定時(shí)器的任務(wù)方法不能有返回值(如果有返回值,spring初始化的時(shí)候會(huì)告訴你有個(gè)錯(cuò)誤、需要設(shè)定一個(gè)proxytargetclass的某個(gè)值為true),不能指向任何的參數(shù);
- 如果該方法需要與應(yīng)用程序上下文的其他對象進(jìn)行交互,通常是通過依賴注入來實(shí)現(xiàn);
- 實(shí)現(xiàn)類上要有組件的注解@Component。
三、使用@Scheduled常見問題
單線程任務(wù)丟失,轉(zhuǎn)為異步線程池
默認(rèn)的 ConcurrentTaskScheduler 計(jì)劃執(zhí)行器采用Executors.newSingleThreadScheduledExecutor() 實(shí)現(xiàn)單線程的執(zhí)行器。因此,對同一個(gè)調(diào)度任務(wù)的執(zhí)行總是同一個(gè)線程。如果任務(wù)的執(zhí)行時(shí)間超過該任務(wù)的下一次執(zhí)行時(shí)間,則會(huì)出現(xiàn)任務(wù)丟失,跳過該段時(shí)間的任務(wù)。上述問題有以下解決辦法:
采用異步的方式執(zhí)行調(diào)度任務(wù),配置 Spring 的 @EnableAsync,在執(zhí)行定時(shí)任務(wù)的方法上標(biāo)注 @Async配置任務(wù)執(zhí)行池,線程池大小 n 的數(shù)量為 單個(gè)任務(wù)執(zhí)行所需時(shí)間 / 任務(wù)執(zhí)行的間隔時(shí)間。如下:
//每30秒執(zhí)行一次
@Async("taskExecutor")
@Scheduled(fixedRate = 1000 * 3)
public void reportCurrentTime(){
System.out.println ("線程" + Thread.currentThread().getName() + "開始執(zhí)行定時(shí)任務(wù)===&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&====》"
+ new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
long start = System.currentTimeMillis();
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- spring 定時(shí)任務(wù)@Scheduled詳解
- 詳解SpringBoot 創(chuàng)建定時(shí)任務(wù)(配合數(shù)據(jù)庫動(dòng)態(tài)執(zhí)行)
- SpringBoot實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)
- SpringBoot中實(shí)現(xiàn)定時(shí)任務(wù)的4種方式詳解
- SpringBoot 定時(shí)任務(wù)遇到的坑
- springboot集成schedule實(shí)現(xiàn)定時(shí)任務(wù)
- Springboot定時(shí)任務(wù)Scheduled重復(fù)執(zhí)行操作
- Spring定時(shí)任務(wù)之fixedRateString的實(shí)現(xiàn)示例
相關(guān)文章
java設(shè)計(jì)模式之裝飾器模式(Decorator)
這篇文章主要為大家詳細(xì)介紹了java設(shè)計(jì)模式之裝飾器模式Decorator,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-01-01
Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表
這篇文章主要為大家詳細(xì)介紹了Java 8實(shí)現(xiàn)任意參數(shù)的單鏈表,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-10-10
SpringBoot+slf4j線程池全鏈路調(diào)用日志跟蹤問題及解決思路(二)
本文主要給大家介紹如何實(shí)現(xiàn)子線程中的traceId日志跟蹤,本文通過封裝Callable為例給大家介紹的非常詳細(xì),需要的朋友一起看看吧2021-05-05

