SpringBoot配置及使用Schedule过程解析
我们在平常项目开发中,经常会用到周期性定时任务,这个时候使用定时任务就能很方便的实现。在SpringBoot中用得最多的就是Schedule。
一、SpringBoot集成Schedule
1、依赖配置
由于Schedule就包含在spring-boot-starter中,所以无需引入其他依赖。
2、启用定时任务
在启动类或者配置类上增加@EnableScheduling注解。
importorg.springframework.boot.SpringApplication; importorg.springframework.boot.autoconfigure.SpringBootApplication; importorg.springframework.scheduling.annotation.EnableScheduling; @EnableScheduling @SpringBootApplication publicclassDemoApplication{ publicstaticvoidmain(String[]args){ SpringApplication.run(DemoApplication.class,args); } }
3、添加定时任务
Schdule支持cron表达式、固定间隔时间、固定频率三种调度方式。
1)cron表达式定时任务
与Linux下定时任务用到的Cron表达式一样。
字段
允许值
允许的特殊字符
秒(Seconds)
0~59的整数
,-*/ 四个字符
分(Minutes)
0~59的整数
,-*/ 四个字符
小时(Hours)
0~23的整数
,-*/ 四个字符
日期(DayofMonth)
1~31的整数(但是你需要考虑该月的天数)
,-*?/LWC 八个字符
月份(Month)
1~12的整数或者JAN-DEC
,-*/ 四个字符
星期(DayofWeek)
1~7的整数或者SUN-SAT(1=SUN)
,-*?/LC# 八个字符
年(可选,留空)(Year)
1970~2099
,-*/ 四个字符
@Component @EnableScheduling publicclassMyCronTask{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MyCronTask.class); @Scheduled(cron="0/1*****") voidcronSchedule(){ logger.info("cronscheduleexecute"); } }
PS:Cron表达式方式配置的定时任务如果其执行时间超过调度频率时,调度器会在下个执行周期执行。如第一次执行从第0秒开始,执行时长3秒,则下次执行为第4秒。
2)固定间隔定时任务
下一次的任务执行时间是从上一次定时任务结束时间开始计算。
@Scheduled(fixedDelay=2) voidfixedDelaySchedule()throwsException{ Thread.sleep(2000); logger.info("fixeddelayscheduleexecute"); }
输出:
2020-04-2323:11:54.362INFO85325---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixeddelayscheduleexecute
2020-04-2323:11:58.365INFO85325---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixeddelayscheduleexecute
2020-04-2323:12:02.372INFO85325---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixeddelayscheduleexecute
2020-04-2323:12:06.381INFO85325---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixeddelayscheduleexecute
3)固定频率定时任务
按照指定频率执行任务
@Scheduled(fixedRate=2000) voidfixedRateSchedule()throwsException{ Thread.sleep(3000); logger.info("fixedratescheduleexecute"); }
输出:
2020-04-2323:16:14.750INFO85328---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixedratescheduleexecute
2020-04-2323:16:17.754INFO85328---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixedratescheduleexecute
2020-04-2323:16:20.760INFO85328---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixedratescheduleexecute
2020-04-2323:16:23.760INFO85328---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixedratescheduleexecute
2020-04-2323:16:26.764INFO85328---[scheduling-1]com.springboot.study.tasks.MyCronTask:fixedratescheduleexecute
PS:当方法的执行时间超过任务调度频率时,调度器会在当前方法执行完成后立即执行下次任务。
二、配置多个定时任务并发执行
1、并行or串行?
缺省状态下,当我们没有给定时任务配置线程池时,Schedule是串行执行,如下:
@Component @EnableScheduling publicclassMyCronTask{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MyCronTask.class); @Scheduled(fixedDelay=2000) voidtask1Schedule()throwsException{ Thread.sleep(2000); logger.info("task1execute"); } @Scheduled(fixedDelay=2000) voidtask2Schedule()throwsException{ Thread.sleep(2000); logger.info("task2execute"); } @Scheduled(fixedDelay=2000) voidtask3Schedule()throwsException{ Thread.sleep(2000); logger.info("task3execute"); } }
输出:
2020-04-2323:19:46.970INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:19:48.973INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:19:50.974INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:19:52.978INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:19:54.984INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:19:56.984INFO85332---[scheduling-1]com.springboot.study.tasks.MyCronTask:task3execute
可以看出来只有一个线程穿行执行所有定时任务。
2、Schedule并行执行配置
定时调度的并行化,有两种配置方式:
1)修改任务调度器默认使用的线程池:添加一个configuration,实现SchedulingConfigurer接口就可以了。
@Configuration publicclassScheduleConfigimplementsSchedulingConfigurer{ @Override publicvoidconfigureTasks(ScheduledTaskRegistrartaskRegistrar){ taskRegistrar.setTaskScheduler(getTaskScheduler()); } @Bean publicTaskSchedulergetTaskScheduler(){ ThreadPoolTaskSchedulertaskScheduler=newThreadPoolTaskScheduler(); taskScheduler.setPoolSize(3); taskScheduler.setThreadNamePrefix("myworker-"); taskScheduler.setWaitForTasksToCompleteOnShutdown(true); returntaskScheduler; } }
再次执行后,输出:
2020-04-2323:33:14.197INFO85461---[myworker-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:33:14.197INFO85461---[myworker-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:33:14.197INFO85461---[myworker-3]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:33:18.203INFO85461---[myworker-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:33:18.203INFO85461---[myworker-3]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:33:18.204INFO85461---[myworker-1]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:33:22.208INFO85461---[myworker-1]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:33:22.208INFO85461---[myworker-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:33:22.208INFO85461---[myworker-3]com.springboot.study.tasks.MyCronTask:task1execute
2)直接将任务交给一步线程池处理:启用@EnableAsync注解,并在每一个定时任务方法上使用@Async注解。
@Component @EnableScheduling @EnableAsync @Async publicclassMyCronTask{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MyCronTask.class); @Scheduled(fixedDelay=2000) voidtask1Schedule()throwsException{ Thread.sleep(2000); logger.info("task1execute"); } @Scheduled(fixedDelay=2000) voidtask2Schedule()throwsException{ Thread.sleep(2000); logger.info("task2execute"); } @Scheduled(fixedDelay=2000) voidtask3Schedule()throwsException{ Thread.sleep(2000); logger.info("task3execute"); } }
输出如下:
2020-04-2323:38:00.614INFO85468---[task-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:38:00.614INFO85468---[task-3]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:38:00.614INFO85468---[task-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:38:02.620INFO85468---[task-4]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:38:02.620INFO85468---[task-5]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:38:02.620INFO85468---[task-6]com.springboot.study.tasks.MyCronTask:task3execute
有上面输出可以看出来这种方式对于每一次定时任务的执行都会创建新的线程,这样对内存资源是一种浪费,严重情况下还会导致服务挂掉,因此为了更好控制线程的使用,我们可以自定义线程池。
首先配置线程池:
@Configuration publicclassMyTaskExecutor{ @Bean(name="myExecutor") publicTaskExecutorgetMyExecutor(){ ThreadPoolTaskExecutortaskExecutor=newThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(3); taskExecutor.setMaxPoolSize(10); taskExecutor.setQueueCapacity(20); taskExecutor.setThreadNamePrefix("myExecutor-"); taskExecutor.initialize(); returntaskExecutor; } }
使用我们自己的线程池:
@Component @EnableScheduling @EnableAsync @Async("myExecutor") publicclassMyCronTask{ privatestaticfinalLoggerlogger=LoggerFactory.getLogger(MyCronTask.class); @Scheduled(fixedDelay=2000) voidtask1Schedule()throwsException{ Thread.sleep(2000); logger.info("task1execute"); } @Scheduled(fixedDelay=2000) voidtask2Schedule()throwsException{ Thread.sleep(2000); logger.info("task2execute"); } @Scheduled(fixedDelay=2000) voidtask3Schedule()throwsException{ Thread.sleep(2000); logger.info("task3execute"); } }
输出:
2020-04-2323:46:47.404INFO85488---[myExecutor-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:46:47.404INFO85488---[myExecutor-3]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:46:47.404INFO85488---[myExecutor-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:46:49.404INFO85488---[myExecutor-3]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:46:49.404INFO85488---[myExecutor-2]com.springboot.study.tasks.MyCronTask:task3execute
2020-04-2323:46:49.404INFO85488---[myExecutor-1]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:46:51.405INFO85488---[myExecutor-2]com.springboot.study.tasks.MyCronTask:task2execute
2020-04-2323:46:51.405INFO85488---[myExecutor-3]com.springboot.study.tasks.MyCronTask:task1execute
2020-04-2323:46:51.405INFO85488---[myExecutor-1]com.springboot.study.tasks.MyCronTask:task3execute
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。