springboot实现定时任务-Scheduling

1.主要总结@Scheduled()注解的三个属性:cron,fixedRate,fixedDelay

cron为cron表达式,用来表示该任务在日期时间维度执行频率,详细可参考cron表达式的文章

fixedRate:代表该任务的执行频率,单位毫秒,无论任务执行耗时多久,总是以该频率执行任务

fixedDelay:代表该任务的执行频率,单位毫秒,在上一次任务执行完后等待x毫秒后执行下次任务

2.开启异步@EnableAsync后使用上述三种属性产生的效果

前提:springboot通过scheduling实现的定时任务使用的线程有自己的线程池,默认大小为1,此时无法满足多个定时任务的情形,因此通常需要手动设置线程池的大小,以10为例。

有以下三种情形

1.使用fixedRate属性不加@Async注解、使用fixedRate属性加@Async注解

2.使用cron不加@Async注解、使用cron属性加@Async注解

3.使用fixedDelay不加@Async注解

@Component @EnableAsync @Slf4j public class ScheduledTasks {      @Scheduled(fixedDelay = 3000) //    @Scheduled(fixedRate = 3000) //    @Scheduled(cron = "0/3 * * * * ?") //    @Async(value = "myAsync")     void contextLoads() throws InterruptedException {         log.info("scheduled1 wait start");         Thread.sleep(4000);         log.info("scheduled1 wait end");         log.info("scheduled task run....      " + Thread.currentThread().getName());     }  //    @Scheduled(cron = "0/3 * * * * ?")     @Scheduled(fixedDelay = 3000) //    @Scheduled(fixedRate = 3000) //    @Async(value = "myAsync")     void scheduled2() throws InterruptedException {         log.info("scheduled2 wait start");         Thread.sleep(4000);         log.info("scheduled2 wait end");         log.info("scheduled task2 run....      " + Thread.currentThread().getName());     } }

3.结论:

1.使用fixedRate加@Async注解和使用cron加@Async注解效果相同

会实现无论任务执行耗时多久,下次任务始终会以规定的频率执行;

上述例子中若为fixedRate,则下次任务开始执行始终是在上次任务开始后的三秒;

若为cron,则下次任务开始执行始终为上次任务开始执行后的三秒,也就是上次任务开始时间为10:23:02,则下次任务开始时间为10:23:05,此种情况不受任务执行耗时影响。

2.使用fixedRate不加@Async注解

此时若每次任务执行耗时比fixedRate的值小,则会在上次任务开始后的fixedRate毫秒后开始执行下次任务;

若每次执行任务耗时比fixedRate的值大,则会在上次任务执行后立刻执行下次任务,因为此时已经超过规定的执行频率的时间,因此需要立刻执行下次任务。

3.使用cron不加@Async注解

此时若每次任务执行耗时比cron表达式所表示的上次任务开始时间与下次任务开始时间的间隔小,则会以cron表达式表示的频率执行任务;

若每次任务执行耗时比cron表达式所表示的上次任务开始时间与下次任务开始时间的间隔大,则下次任务会在上次任务执行完成后再到达cron表达式所表示的任务开始执行的时刻开始执行任务,例如上述例子中上次任务开始时间为10:23:02,任务执行耗时4s,而以cron表达式表示的频率下次的执行时间为10:23:05,但是此时上次任务并没有执行完成,上次任务执行完成的时间为10:23:06,因此下次任务执行需要等到cron表达式表示的下一次任务执行的时刻也就是10:23:08.

4.使用fixedDelay不加@Async注解

使用fixedDelay属性时不能加@Async注解,否则会报错。

此时无论任务执行耗时是多少,下次任务开始执行的时间总是上次任务执行完成后的fixedDelay毫秒。

5.当有多个定时任务时,在保证定时任务线程池数以及异步线程池数足够的情况下,多个定时任务同样遵循上述结论。

6.上述结论中1和4是比较符合开发需要的两种场景。

4.修改定时任务线程池以及自定义异步任务线程池

1.修改定时任务默认的线程池大小

方式一:修改配置文件application.yml 

spring.task.scheduling.pool.size = 10

方式二:配置类

@Configuration public class ScheduleConfig implements SchedulingConfigurer {     @Override     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {         taskRegistrar.setScheduler(Executors.newScheduledThreadPool(50));     } }

2.自定义定时任务的线程池

@Configuration public class ScheduleConfig {       /**      * 此处方法名为Bean的名字,方法名无需固定      * 因为是按TaskScheduler接口自动注入      */     @Bean     public TaskScheduler taskScheduler(){         // Spring提供的定时任务线程池类         ThreadPoolTaskScheduler taskScheduler=new ThreadPoolTaskScheduler();         //设定最大可用的线程数目         taskScheduler.setPoolSize(10);         return taskScheduler;     } }

3.自定义异步任务线程池

@Component public class AsyncScheduledTaskConfig {      @Bean     public Executor myAsync() {         ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();         //最大线程数         executor.setMaxPoolSize(100);         //核心线程数         executor.setCorePoolSize(10);         //任务队列的大小         executor.setQueueCapacity(10);         //线程前缀名         executor.setThreadNamePrefix("task-thread");         //线程存活时间         executor.setKeepAliveSeconds(30);          /**          * 拒绝处理策略          * CallerRunsPolicy():交由调用方线程运行,比如 main 线程。          * AbortPolicy():直接抛出异常。          * DiscardPolicy():直接丢弃。          * DiscardOldestPolicy():丢弃队列中最老的任务。          */         executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());         //线程初始化         executor.initialize();         return executor;     } } 

使用时只需在@Async注解中使用value属性指定线程线程池名称,也就是bean的名称,上述默认为方法名

Chile Address 版权所有
Powered by WordPress