直接上图
![](https://img.haomeiwen.com/i7686832/9a7972c79a5e70b5.png)
spring定时任务是通过JDK的ThreadPoolTaskScheduler实现的。
spring中处理逻辑
- 解析task命名空间,将定时任务的数据通过IOC解析成为BeanDefinition
- 在创建Bean对象时,处理BeanDefinition数据实例化一下对象:
-
CronTask
这个对象中包含了cron任务触发器和需要执行的任务Runnable对象 -
ScheduledMethodRunnable
这个对象中包含了Method和target并且实现Runnable接口这个Runnable接口最后会进入JAVA中的线程池中 -
ThreadPoolTaskScheduler
在spring中创建JAVA的线程池对象,前面创建的CronTask
和ScheduledMethodRunnable
注册到线程池中
-
- 所有的任务都会创建上面的
CronTask
和ScheduledMethodRunnable
然后注册到同一个线程池中ThreadPoolTaskScheduler
- 进入java代码逻辑
java代码逻辑
每一个任务进入ThreadPoolTaskScheduler
。不知道大家有没有想过定时任务执行的方式是如何左右定时执行的?假设现在有1000个任务我怎么知道下一个即将执行的定时任务呢?
方案1(不好的实现方式)
通过一个比较小的时间单位,例如1秒钟遍历一次定时任务队列,查看里面那个任务需要执行。这种方案很容易就被否定了。因为如果数据量比较大,每次遍历队列很有可能1秒钟都无法遍历完毕,而且这种时间也不准确。
方案2(优先级队列)
如果学过堆这种数据结构的同学应该知道堆的最佳实践——优先级队列
堆的定义
- 堆是一个满二叉树,满二叉树最好的存储方式就是数组因为这样查询数据的时间复杂度为O(1)可以根据下标直接访问。
- 堆里面的任意一个父节点的所有子节点要么大于等于(小于)其父节点的数据。下面我画了个图,其中1,2是大顶堆;3是小顶堆;4不是堆
![](https://img.haomeiwen.com/i7686832/8cd89adf0147df66.png)
分析优先级队列在
ThreadPoolTaskScheduler
中的使用。在spring中已经创建的Runnable和触发器。每次向队列中添加一个task的时候需要判断滞后时间最小的数据放到堆顶,这样在从队列中获取任务的时候就可以直接拿堆顶(队首)元素判断队首元素执行时间和当前时间对比,如果滞后时间大那么需要将当前线程利用LockSupper工具将当前线程挂起n毫秒,n毫秒到了之后当前线程继续执行,然后调用Runnable接口的run方法。也就是ScheduledMethodRunnable
的run方法
网友评论