博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Scheduler(Spring)
阅读量:6938 次
发布时间:2019-06-27

本文共 5568 字,大约阅读时间需要 18 分钟。

hot3.png

线程池相关分析可参考   

org.springframework.scheduling.config.TaskNamespaceHandler:注册task命名空间标签解析器

task:annotation-driven       ->AnnotationDrivenBeanDefinitionParsertask:executor                ->ExecutorBeanDefinitionParsertask:scheduler               ->SchedulerBeanDefinitionParsertask:scheduled-tasks         ->ScheduledTasksBeanDefinitionParser 

spring task sample

 

org.springframework.scheduling.config.AnnotationDrivenBeanDefinitionParser

强制单例,不允许有id属性

1.task:annotation-driven2.处理task:annotation-driven属性    mode    executor     scheduler     exceptionHandler     proxyTargetClass3.利用AsyncAnnotationBeanPostProcessor处理@Async    annotation @Async 使用包装了的java的ThreadPoolExecutor executor线程池4.利用ScheduledAnnotationBeanPostProcessor处理@Scheduled    annotation @Scheduled 使用包装了java的ScheduledThreadPoolExecutor scheduler线程池5.对于executor  优先使用自己的属性executor指定的线程池          见AnnotationDrivenBeanDefinitionParser.parse() Line 74~77  如果没有就在上下文中寻找id为taskExecutor或者类为TaskExecutor的线程池          见AnnotationDrivenBeanDefinitionParser.parse() Line 74~77  如果还没有就使用@Async默认的SimpleAsyncTaskExecutor(Sping自己实现的线程不会重用的线程池)          见AnnotationDrivenBeanDefinitionParser.parse() Line 85           和AsyncAnnotationBeanPostProcessor.setBeanFactory()Line148/AsyncAnnotationAdvisor()Line916.对于scheduler  优先使用自己的属性scheduler指定的线程池(定时周期调度器)          见AnnotationDrivenBeanDefinitionParser.parse() Line 97~100  如果没有就在上下文中寻找id为taskScheduler或者类为TaskScheduler的线程池          见AnnotationDrivenBeanDefinitionParser.parse() Line 97~100  如果还没有就使用@Scheduled默认设置的Executors.newSingleThreadScheduledExecutor()          见AnnotationDrivenBeanDefinitionParser.parse() Line 101          和ScheduledAnnotationBeanPostProcessor.finishRegistration() Line225/ScheduledTaskRegistrar.scheduleTasks()Line336~339

 

org.springframework.scheduling.config.ExecutorBeanDefinitionParser

非强制单例

1.task:executor,对应ThreadPoolTaskExecutor,实际上是包装了的ThreadPoolExecutor2.处理task:executor属性    keep-alive 对应ThreadPoolExecutor.keepAliveTime    queue-capacity 对应ThreadPoolExecutor.workQueue    pool-size 对应ThreadPoolExecutor.corePoolSize和ThreadPoolExecutor.maximumPoolSize,若没有指定默认值,默认是1-Integer.MAX

 

org.springframework.scheduling.config.SchedulerBeanDefinitionParser

非强制单例

1.task:scheduler,对应ThreadPoolTaskScheduler,实际上是包装了的ScheduledThreadPoolExecutor2.处理task:scheduler属性    pool-size 对应ThreadPoolExecutor.corePoolSize和ThreadPoolExecutor.maximumPoolSize,若没有指定默认值,默认是1-Integer.MAX

 

org.springframework.scheduling.config.ScheduledTasksBeanDefinitionParser

强制单例对象,不允许有id属性

1.task:scheduled-tasks,对应ContextLifecycleScheduledTaskRegistrar2.task:scheduled,对应ScheduledMethodRunnable3.处理task:scheduled-tasks属性    scheduler,对应ThreadPoolTaskScheduler,实际上包装的ScheduledThreadPoolExecutor4.处理task:scheduled属性    ref    method    cron    fixed-delay    fixed-rate    trigger    initial-delay5.对于scheduler    优先使用自己的属性scheduler指定的线程池    如果没有就在上下文中寻找id为taskScheduler的线程池         见ScheduledTasksBeanDefinitionParser.doParse() Line 124~127    如果还没有就是用默认的单线程线程池Executors.newSingleThreadScheduledExecutor();       见ScheduledTaskRegistrar.scheduleTasks() Line 336~339

三种周期任务均是在每次任务执行完成后才会计算该周期任务下一次执行时间点

  • FixedDelay任务,在当前任务执行完后再计算下一次开始执行的时间点(需要当前任务执行完成的时间点
  • Cron任务,由对象CronSequenceGenerator来计算下一次开始执行的时间点,也是在当前任务执行完成后再计算下一次的执行时间点(也需要当前任务执行完成的时间点
  • FixedRate任务,可以直接计算下次甚至每次开始执行的时间点,但也是在任务执行完后再计算下一次开始执行的时间点(不需要当前任务执行完成的时间点)

三种周期任务计算下一次执行时间点的依据不全相同

  • FixedDelay任务,基于上次执行完时的时间点+delay配置计算下次开始执行的时间点
  • Cron任务,基于上次执行完时的时间点+cron配置计算下次开始执行的时间点
  • FixedRate任务,基于执行开始的时间点+rate配置计算下一次开始执行的时间点

三种周期任务中任何一个周期任务在等待队列里最多只有一个副本,要么在队列里等待执行,要么在worker线程里正在执行或者等待到时执行

如果任务因为worker线程不够用而被延期(FixedDelay和Cron延期执行只是一种效果,FixRate累积执行也只是一种效果,实际上在任务上一次调度还没有执行完或者还没有被调度,等待队列里是不会存放该周期任务下一次调度的,依据ScheduledThreadPoolExecutor的实现原理,每一个周期任务至多只会有一个副本<该副本要么在执行,要么在等待任务队列里>):

  • 对于FixedDelay而言,至多只有一个被耽误的任务,该任务将在获得worker线程时执行.(只要该周期任务存在且已到期或者过期,就会被执行)所以FixedDelay会存在至多一次被耽误的任务,如果执行完该次被耽误的任务,后续空闲worker线程一直够用,其后的同周期下一次调度将会准时
  • 对于Cron而言,至多只有一个被耽误的任务,该任务将在获得worker线程时执行.(只要该周期任务存在且已到期或者过期,就会被执行)所以Cron会存在至多一次被耽误的任务,如果执行完该次被耽误的任务,后续空闲worker线程一直够用,其后的同周期下一次调度将会准时
  • 对于FixedRate而言(实际上也至多只有一个被耽误的任务,该任务将在获得worker线程时执行)但开始执行时间点必须一一累加,直至当前乃至下一次的执行时间点,即中间被耽误的周期任务序列仍会被一一创建、添加、调度和执行. 因为只要该周期任务存在且已到期或者过期,都会被执行,好像“FixedRate积存了很多被耽误的任务在队列里”,然后这些被耽误的任务也最终执行了。但实际上FixedRate也只是最多存了一次被耽误的任务,如果后续空闲worker线程一直够用,其后的同周期下一次调度仍可能已经延误,被延误的任务又被添加到等待队列然后被快速调度执行,到计算的开始执行时间点超过当前时间;(这种算法是一种保护内存的算法,避免同周期任务对象无限创建)
  • worker线程执行任务主流程ScheduledThreadPoolExecutor.FutureScheduledTask.run() 
public void run() {            boolean periodic = isPeriodic();                      if (!canRunInCurrentRunState(periodic))                cancel(false);            else if (!periodic)                ScheduledFutureTask.super.run();                             else if (ScheduledFutureTask.super.runAndReset()) {  //运行任务主体,运行完后
<不管成功失败>
才会计算下一次执行时间点,进而重新进任务队列 setNextRunTime(); //计算下一次执行时间点 reExecutePeriodic(outerTask); //添加任务至等待队列 } }

所有还没调度的任务<即任务等待队列workQueue里的对象个数>总数永远不会大于不同周期任务数

  • 线程池里正在运行的worker线程个数永远不会大于不同周期任务数
  • 同一个周期任务上一次没有执行完,任务等待队列里是不会有该周任务的下一次调度对象的(即如果上一次还没执行,或者没有执行完,后续的同周期任务永远不会执行!因为只有任务执行完才会添加新的任务到队列,任务等待队列里不会存在该周期任务的信息)
  • 基于以上原因,不会有两个及两个以上worker线程同时执行一个周期任务的同一次调度
  • 基于ScheduledThreadPoolExecutor的实现原理,也不会有两个及两个以上worker线程同时执行同一个周期任务的多次调度
  • 线程池的worker线程个数可能设置的很大,超过了不同周期任务数,但其大部分应该是处于空闲状态,即没有运行任务
  • 由此可以得出结论,线程池的corePoolSize个数设置超过已知不同周期任务数,意义不大(间接线程池线程复用的原则)
  • 如果corePoolSize大于或者等于不同周期任务数,但存在某些任务延期执行或者没有执行,问题原因不会是不同周期任务竞争线程池里的worker线程,而是在于该任务本身出了问题(该任务本身执行时间过长,甚至bolck住了)

转载于:https://my.oschina.net/igooglezm/blog/757203

你可能感兴趣的文章
内部控制
查看>>
iOS地图选址
查看>>
我的友情链接
查看>>
自动监控linux服务器负载并重启Web服务的脚本
查看>>
四、Windows Server 2012R2 Hyper-v虚拟交换机的创建与管理
查看>>
java 运算顺序
查看>>
天涯LVS部署
查看>>
eclipse不能自动编译工程的解决方法
查看>>
最好用的cisco路由模拟器 debianIOL
查看>>
Shpinx在PHPCMS里的使用及配置
查看>>
Linux Oracle Rac 10G 搭建& Patch
查看>>
django models.py模块的外部引用
查看>>
VMware虚拟化技术培训(8) 虚拟机管理之二
查看>>
spring内部各模块jar包依赖
查看>>
Apache与Nginx网络模型对比
查看>>
Java 二重循环实现对象去重
查看>>
Supporting Python 3(支持python3)——序
查看>>
从零开始-打造自己的虚拟实验室-2
查看>>
js 完美兼容浏览器的复制功能
查看>>
jdk1.6下使用sardine和jackrabbit-webdav的问题
查看>>