SpringBoot使用Scheduling實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼
springboot實(shí)現(xiàn)定時(shí)任務(wù)
開(kāi)啟springboot定時(shí)任務(wù)
- springboot實(shí)現(xiàn)定時(shí)任務(wù)很簡(jiǎn)單,只需要在啟動(dòng)類上加上
@EnableScheduling
就可以
/** * @author liouwb */ @SpringBootApplication @EnableScheduling public class SchedulerApplication{ public static void main(String[] args) { SpringApplication.run(SchedulerApplication.class, args); } }
- 編寫(xiě)測(cè)試類
/** * @author liouwb */ @Slf4j @Component public class TestJob { /** * 定時(shí)任務(wù)-串行 * 固定一秒執(zhí)行一次 * * @author liouwb */ @Scheduled(cron = "0/1 * * * * ?") public void testTask1() { log.info("測(cè)試任務(wù)-1"); } }
- 執(zhí)行結(jié)果
- 下面測(cè)試,如果讓每次任務(wù)執(zhí)行5秒
/** * 定時(shí)任務(wù)-串行 * 固定一秒執(zhí)行一次 * * @author liouwb */ @Scheduled(cron = "0/1 * * * * ?") public void testTask1() throws InterruptedException { // 讓每次任務(wù)執(zhí)行5秒 Thread.sleep(5 * 1000); log.info("測(cè)試任務(wù)-1"); }
- 想要的結(jié)果是1一秒執(zhí)行一次
- 實(shí)際執(zhí)行結(jié)果,是6秒執(zhí)行一次,線程串行執(zhí)行
- 未達(dá)到想要的接口
原因分析:
@EnableScheduling
注解默認(rèn)使用的是ThreadPoolTaskScheduler
線程池,默認(rèn)線程數(shù)是1- 下面我們看下源碼
- 我們看先
@EnableScheduling
注解
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }
- 看下
SchedulingConfiguration
類
@Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }
- 看下
ScheduledAnnotationBeanPostProcessor
類
public ScheduledAnnotationBeanPostProcessor() { this.registrar = new ScheduledTaskRegistrar(); }
- 看下
ScheduledTaskRegistrar
類,這里使用的是TaskScheduler
線程池 - 默認(rèn)的是
ThreadPoolTaskScheduler
配置線程池,讓定時(shí)任務(wù)指定并發(fā)執(zhí)行
- 配置線程池,實(shí)現(xiàn)
SchedulingConfigurer
接口,實(shí)現(xiàn)configureTasks
方法
/** * 線程池配置 * * @author liouwb * @time 2023-07-27 */ @Configuration public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(taskScheduler()); } @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); // 設(shè)置線程池?cái)?shù)量 taskScheduler.setPoolSize(10); // 設(shè)置線程池前綴 taskScheduler.setThreadNamePrefix("parallelScheduler-"); return taskScheduler; } }
- 執(zhí)行結(jié)果
先要線程異步執(zhí)行
在啟動(dòng)類上添加 @EnableAsync
注解
/** * @author liouwb */ @SpringBootApplication @EnableAsync @EnableScheduling public class SchedulerApplication{ public static void main(String[] args) { SpringApplication.run(SchedulerApplication.class, args); } }
- 再方法上添加
@Async
注解便可以讓方法異步執(zhí)行
/** * @author liouwb */ @Slf4j @Component public class TestJob { /** * 定時(shí)任務(wù)-串行 * 固定一秒執(zhí)行一次 * * @author liouwb */ @Scheduled(cron = "0/1 * * * * ?") public void testTask1() throws InterruptedException { // 讓每次任務(wù)執(zhí)行5秒 Thread.sleep(5 * 1000); log.info("測(cè)試任務(wù)-1"); } @Async @Scheduled(cron = "0/1 * * * * ?") public void testTask2() { log.info("測(cè)試任務(wù)-2"); } }
- 執(zhí)行結(jié)果,可以看到異步線程和并未用到設(shè)置的線程池
springboot異步線程池設(shè)置
springboot
異步線程池默認(rèn)使用的是 ThreadPoolTaskExecutor
ThreadPoolTaskExecutor
和 ThreadPoolTaskScheduler
都在 org.springframework.scheduling.concurrent
下
``
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AsyncConfigurationSelector.class) public @interface EnableAsync {
斷點(diǎn)可以看到默認(rèn)的異步線程池,前綴為 taskScheduler-
,默認(rèn)核心線程數(shù)為 10
默認(rèn)線程池名稱
- 下面我們自己配置異步線程池
/** * 線程池配置 * * @author liouwb */ @Configuration public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(taskScheduler()); } @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); // 設(shè)置線程池前綴 taskScheduler.setThreadNamePrefix("parallelScheduler-"); return taskScheduler; } /** * 配置異步線程池 * * @author liouwb * @rutern org.springframework.core.task.TaskExecutor */ @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設(shè)置核心線程數(shù) executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()); // 設(shè)置最大線程數(shù) executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置隊(duì)列容量 executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置線程活躍時(shí)間(秒) executor.setKeepAliveSeconds(10); // 設(shè)置默認(rèn)線程名稱 executor.setThreadNamePrefix("ansyScheduled-"); // 設(shè)置拒絕策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
- 執(zhí)行結(jié)果,可以看到配置的線程池都生效了
指定線程池執(zhí)行任務(wù)
- 可以設(shè)置多個(gè)線程池
/** * 線程池配置 * * @author liouwb * @time 2023-07-27 */ @Configuration public class SchedulerConfig implements SchedulingConfigurer { @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { taskRegistrar.setScheduler(taskScheduler()); } @Bean public TaskScheduler taskScheduler() { ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); taskScheduler.setPoolSize(10); // 設(shè)置線程池前綴 taskScheduler.setThreadNamePrefix("parallelScheduler-"); return taskScheduler; } /** * 配置異步線程池 * * @author liouwb * @rutern org.springframework.core.task.TaskExecutor */ @Bean public TaskExecutor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設(shè)置核心線程數(shù) executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()); // 設(shè)置最大線程數(shù) executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置隊(duì)列容量 executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置線程活躍時(shí)間(秒) executor.setKeepAliveSeconds(10); // 設(shè)置默認(rèn)線程名稱 executor.setThreadNamePrefix("ansyScheduled-"); // 設(shè)置拒絕策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } /** * 配置異步線程池2 * * @author liouwb * @rutern org.springframework.core.task.TaskExecutor */ @Bean public TaskExecutor taskExecutor2() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設(shè)置核心線程數(shù) executor.setCorePoolSize(Runtime.getRuntime().availableProcessors()); // 設(shè)置最大線程數(shù) executor.setMaxPoolSize(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置隊(duì)列容量 executor.setQueueCapacity(Runtime.getRuntime().availableProcessors() * 10); // 設(shè)置線程活躍時(shí)間(秒) executor.setKeepAliveSeconds(10); // 設(shè)置默認(rèn)線程名稱 executor.setThreadNamePrefix("異步線程池2-"); // 設(shè)置拒絕策略 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務(wù)結(jié)束后再關(guān)閉線程池 executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
- 在執(zhí)行的時(shí)候指定線程池的名稱
/** * @author liouwb */ @Slf4j @Component public class TestJob { /** * 定時(shí)任務(wù)-串行 * 固定一秒執(zhí)行一次 * * @author liouwb */ @Scheduled(cron = "0/1 * * * * ?") public void testTask1() throws InterruptedException { // 讓每次任務(wù)執(zhí)行5秒 Thread.sleep(5 * 1000); log.info("測(cè)試任務(wù)-1"); } /** * 異步執(zhí)行 * * @author liouwb */ @Async @Scheduled(cron = "0/1 * * * * ?") public void testTask2() { log.info("測(cè)試任務(wù)-2"); } /** * 異步執(zhí)行 * 指定使用taskExecutor2線程池 * * @author liouwb */ @Async(value = "taskExecutor2") @Scheduled(cron = "0/1 * * * * ?") public void testTask3() { log.info("測(cè)試任務(wù)-指定線程池-3"); } }
- 執(zhí)行結(jié)果
以上就是SpringBoot使用Scheduling實(shí)現(xiàn)定時(shí)任務(wù)的示例代碼的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot Scheduling定時(shí)任務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- Spring中@EnableScheduling實(shí)現(xiàn)定時(shí)任務(wù)代碼實(shí)例
- Spring中的@EnableScheduling定時(shí)任務(wù)注解
- SpringBoot注解@EnableScheduling定時(shí)任務(wù)詳細(xì)解析
- springboot通過(guò)SchedulingConfigurer實(shí)現(xiàn)多定時(shí)任務(wù)注冊(cè)及動(dòng)態(tài)修改執(zhí)行周期(示例詳解)
- Spring定時(shí)任務(wù)關(guān)于@EnableScheduling的用法解析
- springboot項(xiàng)目使用SchedulingConfigurer實(shí)現(xiàn)多個(gè)定時(shí)任務(wù)的案例代碼
- SpringBoot使用SchedulingConfigurer實(shí)現(xiàn)多個(gè)定時(shí)任務(wù)多機(jī)器部署問(wèn)題(推薦)
- Spring Scheduling本地任務(wù)調(diào)度設(shè)計(jì)與實(shí)現(xiàn)方式
相關(guān)文章
java虛擬機(jī)之JVM調(diào)優(yōu)詳解
這篇文章主要介紹了java虛擬機(jī)之JVM調(diào)優(yōu)詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)Java虛擬機(jī)的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04springboot后端配置多個(gè)數(shù)據(jù)源、Mysql數(shù)據(jù)庫(kù)的便捷方法
實(shí)現(xiàn)springboot 后端配置多個(gè)數(shù)據(jù)源、Mysql數(shù)據(jù)庫(kù),只需要新建 Mapper、實(shí)體類 相應(yīng)的文件夾,將不同數(shù)據(jù)源的文件保存到對(duì)應(yīng)的文件夾下,添加綁定數(shù)據(jù)庫(kù)配置Config,就可以輕松完成2021-08-08啟動(dòng)異常invalid constant type:15的解決方案
今天小編就為大家分享一篇關(guān)于啟動(dòng)異常invalid constant type:15的解決方案,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2018-12-12Spring實(shí)戰(zhàn)之Bean銷(xiāo)毀之前的行為操作示例
這篇文章主要介紹了Spring實(shí)戰(zhàn)之Bean銷(xiāo)毀之前的行為操作,結(jié)合實(shí)例形式分析了spring在bean銷(xiāo)毀之前的行為相關(guān)設(shè)置與使用技巧,需要的朋友可以參考下2019-11-11Java Process與Runtime()的使用及調(diào)用cmd命令阻塞的解決方案
這篇文章主要介紹了Java Process與Runtime()的使用及調(diào)用cmd命令阻塞的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-06-06SpringBoot項(xiàng)目設(shè)置斷點(diǎn)debug調(diào)試無(wú)效忽略web.xml問(wèn)題的解決
這篇文章主要介紹了SpringBoot項(xiàng)目設(shè)置斷點(diǎn)debug調(diào)試無(wú)效忽略web.xml問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-08-08SpringBoot整合Minio的過(guò)程(支持公有及私有bucket)
Bucket 是存儲(chǔ)Object的邏輯空間,每個(gè)Bucket之間的數(shù)據(jù)是相互隔離的,對(duì)用戶而言,相當(dāng)于存放文件的頂層文件夾,這篇文章主要介紹了SpringBoot整合Minio的過(guò)程(支持公有及私有bucket),需要的朋友可以參考下2025-03-03