剛剛看了下Spring Boot實現(xiàn)定時任務的文章,感覺還不錯稚机。Spring Boot 使用Spring自帶的Schedule來實現(xiàn)定時任務變得非常簡單和方便染簇。在這里個大家分享下。
開啟緩存注解
@SpringBootApplication
@EnableScheduling //開啟定時任務
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
編寫定時任務
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
@Slf4j
public class ScheduledTasks {
// cron接受cron表達式瘸羡,根據(jù)cron表達式確定定時規(guī)則
@Scheduled(cron="0/5 * * * * ? ") //每5秒執(zhí)行一次
public void testCron() {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.info(sdf.format(new Date())+"*********每5秒執(zhí)行一次");
}
}
任務完成
啟動項目府阀,查看控制臺打印信息,發(fā)現(xiàn)定時任務已經(jīng)生效缆镣。spring boot 和Scheduled整合完畢。
存在問題
但是后來發(fā)現(xiàn)個問題试浙,通過同時測試幾個任務發(fā)現(xiàn)董瞻,所有的任務都是在同一個線程池中的同一個線程來完成的。在實際開發(fā)過程中田巴,我們當然不希望所有的任務都運行在一個線程中钠糊。
@Scheduled(cron="0/1 * * * * ? ") //每1秒執(zhí)行一次
public void testCron1() {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
logger.info(sdf.format(new Date())+"*********每1秒執(zhí)行一次");
}
@Scheduled(cron="0/2 * * * * ? ") //每2秒執(zhí)行一次
public void testCron2() {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
logger.info(sdf.format(new Date())+"*********每2秒執(zhí)行一次");
}
@Scheduled(cron="0/3 * * * * ? ") //每3秒執(zhí)行一次
public void testCron3() {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
logger.info(sdf.format(new Date())+"*********每3秒執(zhí)行一次");
}
@Scheduled(cron="0/4 * * * * ? ") //每4秒執(zhí)行一次
public void testCron4() {
DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
logger.info(sdf.format(new Date())+"*********每4秒執(zhí)行一次");
}
解決方案
那么,怎么設計成多線程實現(xiàn)并發(fā)呢壹哺?在網(wǎng)上看到過這樣的解決方案眠蚂。通過ScheduleConfig配置文件實現(xiàn)SchedulingConfigurer接口,并重寫setSchedulerfang方法斗躏,我們嘗試著配置了一下。
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
//當然了昔脯,這里設置的線程池是corePoolSize也是很關鍵了啄糙,自己根據(jù)業(yè)務需求設定
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(5));
/**為什么這么說呢?
假設你有4個任務需要每隔1秒執(zhí)行云稚,而其中三個都是比較耗時的操作可能需要10多秒隧饼,而你上面的語句是這樣寫的:
taskRegistrar.setScheduler(newScheduledThreadPool(3));
那么仍然可能導致最后一個任務被阻塞不能定時執(zhí)行
**/
}
}
整合成功
這樣就完成了多線程并發(fā)的配置?我們啟動項目通過控制臺輸出信息驗證一下結果静陈,最后發(fā)現(xiàn)所有的任務都在同一個線程池但不同線程中完成燕雁,說明這個方案完全可行,這樣鲸拥,我們就完成了spring boot 多線程并發(fā)定時任務拐格。
注
@Scheduled所支持的參數(shù):
1.cron:cron表達式,指定任務在特定時間執(zhí)行刑赶;
2.fixedDelay:表示上一次任務執(zhí)行完成后多久再次執(zhí)行捏浊,參數(shù)類型為long,單位ms撞叨;
3.fixedDelayString:與fixedDelay含義一樣金踪,只是參數(shù)類型變?yōu)镾tring浊洞;
4.fixedRate:表示按一定的頻率執(zhí)行任務,參數(shù)類型為long胡岔,單位ms法希;
5.fixedRateString: 與fixedRate的含義一樣,只是將參數(shù)類型變?yōu)镾tring靶瘸;
6.initialDelay:表示延遲多久再第一次執(zhí)行任務苫亦,參數(shù)類型為long,單位ms奕锌;
7.initialDelayString:與initialDelay的含義一樣著觉,只是將參數(shù)類型變?yōu)镾tring;
8.zone:時區(qū)惊暴,默認為當前時區(qū)饼丘,一般沒有用到。Cron表達式范例:
每隔5秒執(zhí)行一次:*/5 * * * * ?
每隔1分鐘執(zhí)行一次:0 */1 * * * ?
每天23點執(zhí)行一次:0 0 23 * * ?
每天凌晨1點執(zhí)行一次:0 0 1 * * ?
每月1號凌晨1點執(zhí)行一次:0 0 1 1 * ?
每月最后一天23點執(zhí)行一次:0 0 23 L * ?
每周星期天凌晨1點實行一次:0 0 1 ? * L
在26分辽话、29分肄鸽、33分執(zhí)行一次:0 26,29,33 * * * ?
每天的0點、13點油啤、18點典徘、21點都執(zhí)行一次:0 0 0,13,18,21 * * ?
其實不會Cron表達式也不用擔心,網(wǎng)上有好多在線Cron生成器益咬,我們完全可以通過在線生成器生成符合要求的cron逮诲,也很方便。