spring定时任务原理

摘要:
可以开启并行调度,springboot中的使用方式:这种模式每次任务执行都会创建一个线程去执行。")@Asyncpublicvoidsc1(){System.out.println;}}风险:如果某个定时任务出现死循环或者执行时间过长而出发时间较短,会导致线程数量不可控。如果自己定义了ScheduledExecutorService,会使用自己定义的线程池,否则ScheduledTaskRegistrar#afterPropertiesSet创建一个单线程的定时任务执行器ScheduledExecutorService,注入到ConcurrentTaskScheduler中,然后通过taskScheduler执行定时任务。

参考文章:https://juejin.im/post/5b64448af265da0f7f44c201

https://juejin.im/post/5e338ebae51d4558864b1ca0

1、开发中使用时要注意的点

(0)spring定时任务执行原理实际使用的是JDK自带的ScheduledExecutorService

(1)spring默认使用单线程的线程池去执行定时任务,所以如果某个任务执行时间过长,会导致其他定时任务阻塞无法执行。

(2)可以开启并行调度,springboot中的使用方式:这种模式每次任务执行都会创建一个线程去执行。

@EnableAsync
@EnableScheduling
@SpringBootApplication
public classQuickMediaApplication {

    public static voidmain(String[] args) {
        SpringApplication.run(QuickMediaApplication.class, args);
    }

    @Scheduled(cron = "0/1 * * * * ?")
    @Async
    public voidsc1()  {
        System.out.println(Thread.currentThread().getName() + " | sc1 " +System.currentTimeMillis());
    }
}

风险:如果某个定时任务出现死循环或者执行时间过长而出发时间较短,会导致线程数量不可控。

(3)最稳妥的处理方式:自定义任务执行的线程池,如下:

普通spring配置:

@Bean
publicAsyncTaskExecutor asyncTaskExecutor() {
    ThreadPoolTaskExecutor executor = newThreadPoolTaskExecutor();
    executor.setThreadNamePrefix("task-schedule-");
    executor.setMaxPoolSize(10);
    executor.setCorePoolSize(3);
    executor.setQueueCapacity(0);
    executor.setRejectedExecutionHandler(newThreadPoolExecutor.AbortPolicy());
    returnexecutor;
}

或

@Bean
publicScheduleExecutorService scheduleExecutorService{
    return Executors.new ScheduleThreadPool(10);    
}

springboot中配置:

spring.task.scheduling.pool.size=10spring.task.scheduling.thread-name-prefix=task-schedule-

2、源码分析

通过监听IOC容器初始化事件,扫描所有Bean中带有@Scheduled注解的方法,然后封装成Task子类放置到ScheduledTaskRegistrar中。如果自己定义了ScheduledExecutorService,会使用自己定义的线程池,否则ScheduledTaskRegistrar#afterPropertiesSet 创建一个单线程的定时任务执行器 ScheduledExecutorService,注入到 ConcurrentTaskScheduler中,然后通过 taskScheduler 执行定时任务。

public classScheduledAnnotationBeanPostProcessor
        implementsScheduledTaskHolder, MergedBeanDefinitionPostProcessor, DestructionAwareBeanPostProcessor,
        Ordered, EmbeddedValueResolverAware, BeanNameAware, BeanFactoryAware, ApplicationContextAware,
        SmartInitializingSingleton, ApplicationListener<ContextRefreshedEvent>, DisposableBean {
................ @Override
public voidonApplicationEvent(ContextRefreshedEvent event) { if (event.getApplicationContext() == this.applicationContext) { //Running in an ApplicationContext -> register tasks this late... //giving other ContextRefreshedEvent listeners a chance to perform //their work at the same time (e.g. Spring Batch's job registration). finishRegistration(); } } private voidfinishRegistration() { if (this.scheduler != null) { this.registrar.setScheduler(this.scheduler); } .......................if (this.registrar.hasTasks() && this.registrar.getScheduler() == null) { Assert.state(this.beanFactory != null, "BeanFactory must be set to find scheduler by type"); try{ //Search for TaskScheduler bean... this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, false)); } catch(NoUniqueBeanDefinitionException ex) { logger.debug("Could not find unique TaskScheduler bean", ex); try{ this.registrar.setTaskScheduler(resolveSchedulerBean(beanFactory, TaskScheduler.class, true)); } catch(NoSuchBeanDefinitionException ex2) { if(logger.isInfoEnabled()) { logger.info("More than one TaskScheduler bean exists within the context, and " + "none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " + "(possibly as an alias); or implement the SchedulingConfigurer interface and call " + "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +ex.getBeanNamesFound()); } } } catch(NoSuchBeanDefinitionException ex) { logger.debug("Could not find default TaskScheduler bean", ex); //Search for ScheduledExecutorService bean next... try{ this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, false)); } catch(NoUniqueBeanDefinitionException ex2) { logger.debug("Could not find unique ScheduledExecutorService bean", ex2); try{ this.registrar.setScheduler(resolveSchedulerBean(beanFactory, ScheduledExecutorService.class, true)); } catch(NoSuchBeanDefinitionException ex3) { if(logger.isInfoEnabled()) { logger.info("More than one ScheduledExecutorService bean exists within the context, and " + "none is named 'taskScheduler'. Mark one of them as primary or name it 'taskScheduler' " + "(possibly as an alias); or implement the SchedulingConfigurer interface and call " + "ScheduledTaskRegistrar#setScheduler explicitly within the configureTasks() callback: " +ex2.getBeanNamesFound()); } } } catch(NoSuchBeanDefinitionException ex2) { logger.debug("Could not find default ScheduledExecutorService bean", ex2); //Giving up -> falling back to default scheduler within the registrar... logger.info("No TaskScheduler/ScheduledExecutorService bean found for scheduled processing"); } } } this.registrar.afterPropertiesSet(); } }
if (this.taskScheduler == null) {
      this.localExecutor =Executors.newSingleThreadScheduledExecutor();
      this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
  1. Spring定时任务执行原理实际使用的是JDK自带的ScheduledExecutorService

免责声明:文章转载自《spring定时任务原理》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇阿里云常用产品汇总及解释-copy三篇文章了解 TiDB 技术内幕——说计算下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Shiro认证流程

认证流程图解: 身份认证流程 1、首先调用Subject.login(token) 进行登录,其会自动委托给SecurityManager 2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator 进行身份验证; 3、Authenticator 才是真正的身份验证者,ShiroAPI 中核心的身份认证入口点,此处可...

Spring:No bean named 'beanScope' is defined

初学Spring,“No bean named 'beanScope' is defined”这个问题困扰了我好几个小时,查资料无果后,重写好几遍代码后发现问题居然是配置文件不能放在包里。。。要放在src的直接目录下。。。心碎了一地。。。 使用的是  windows 10 / eclipse 4.5.2 /Spring-framework-4.3.0/ 下...

@EnableAsync@Async使用总结

我们在使用多线程的时候,往往需要创建Thread类,或者实现Runnable接口,如果要使用到线程池,我们还需要来创建Executors,在使用spring中,已经给我们做了很好的支持。只要要@EnableAsync就可以使用多线程。使用@Async就可以定义一个线程任务。通过spring给我们提供的ThreadPoolTaskExecutor就可以使用线...

eclipse+maven+ssm框架搭建

eclipse+maven+ssm框架 0、系统环境 1)Windows 10 企业版 2)JDK 1.8.0_131 3)Eclipse Java EE IDE for Web Developers  Version: Neon.3 Release (4.6.3) 4)Tomcat 8.5 1、maven下载及配置 maven的下载地址:http:...

springMVC ——Controller配置方式

一.手动配置方式(开发中主要用注解方式,可以直接看标题二:注解方式)1.web.xml中DispatcherServlet控制器的的配置 SpringMVC也是一种基于请求驱动的WEB框架,并且使用了前端控制器的设计模式。前端控制器就是DispatcherServlet控制器,只要满足web.xml文件中的【url-pattern】的规则,这个请求就会交给...

springboot-quartz普通任务与可传参任务

两者区别与作用:普通任务:总调度(SchedulerFactoryBean)--> 定时调度器(CronTriggerFactoryBean) --> 调度明细自定义执行方法bean(MethodInvokingJobDetailFactoryBean) -->调度bean(我们定义的job类)可传参任务:总调度(SchedulerFac...