Hutool cron拓展阅读总结

定时任务

最近在阅读Hutool源码中的cron部分,其提供了简单的定时器,于是我展开阅读一些资料,总结如下。

简单定时器

这种方式最简单,如果想定期执行一个操作,只需要起一个定时器,设置时间间隔,设置回调函数,让它跑就完了.在定时任务非常少的情况下,这种方式没什么问题.如果定时任务的数目很大,并且都有不同的周期,那就产生了非常多的定时器, 不易维护,效率低下。

img

任务队列

为了不产生过多的定时器,只使用一个定时器,将所有的定时任务放到一个队列中,每个定时任务都保存一份自己的定时信息,定时器每隔一个周期轮询一遍队列中的所有任务,如果任务的超时时间已到,则执行该任务,如果超时时间还没到,则将该任务的定时信息减掉一个定时器的时间间隔,等到完全减为0时,该任务就可以被执行了, 这个定时器一直这么执行并轮询下去.假设当前定时任务总数有100个,那定时器每个周期会遍历一个100个元素的队列,听上去还可以,那要有1000个的时候,10000个时候, 可扩展性也低。

img

优化任务队列

为了解决任务队列中任务太多,一个定时器压力太大的问题,我们继续对其进行优化,既然所有的定时任务都放在一个队列下不太行,那就对定时任务进行分类,将定时周期相同的任务放在同一个定时器下,这样每个定时器的压力就会大大减小,每个定时器只负责自己周期内的任务,不负责其他周期的任务.但是如果每个任务的周期都相同,还是要产生很多定时器,还是无法从根本上解决问题...

img

时间轮

时间轮的核心是,轮询线程不再是负责遍历所有任务,而只在负责处于其当前时间上的任务.就像钟表一样,时间轮有一个指针会一直旋转,每转到一个新的时间,就去执行挂在这一时刻下的所有任务,当然,这些任务通常是交给其他线程去做,指针要做的只是继续往下转,不会关心任务的执行进度.

一个简单的时间轮是一个由计时任务桶组成的环形列表。设 u 为时间单位。一个大小为 n 的时间轮有 n 个桶,并且可以在 n * u 的时间间隔内持有计时任务。每个桶持有落在相应时间范围内的计时任务。开始时,第一个桶持有 [0, u) 的任务,第二个桶持有 [u, 2u) 的任务,……,第 n 个桶持有 [u * (n - 1), u * n) 的任务。每隔一个时间单位 u,计时器就会滴答一下,并移动到下一个桶,然后到期所有该桶内的计时任务。因此,计时器永远不会将任务插入当前时间的桶,因为它已经过期了。计时器立即执行过期的任务。然后清空的桶可用于下一轮,所以如果当前的桶是为时间 t,它在滴答(Tick)之后变成了时间段 [t + u * n, t + (n + 1) * u) 的桶。时间轮的插入/删除(启动计时器/停止计时器)成本为 O(1),而基于优先队列的计时器,如 java.util.concurrent.DelayQueue 和 java.util.Timer,插入/删除成本为 O(log n)。注意,DelayQueue 和 Timer 都不支持随机删除。

Hierarchical timing wheels

img

简单的时间轮的主要缺点是它假设一个计时器请求在当前时间的 n * u 时间间隔内。如果计时器请求超出了这个间隔,就会发生溢出。

Hutool使用了层级时间轮用于处理这种溢出。它是按层级组织的时间轮,将溢出任务委托给上层的时间轮处理。最低层具有最精细的时间分辨率。随着我们向上移动层级,时间分辨率变得更粗。如果一个层级的时间轮分辨率是 u,大小是 n,则第二层的分辨率应该是 n * u,第三层是 n² * u,以此类推。在每个层级,溢出任务被委托给更高一级的时间轮。当高一级的时间轮滴答作响时,它将计时任务重新插入到较低的层级。溢出轮可以根据需要创建。当溢出桶中的一个桶过期时,其中的所有任务都会递归地重新插入计时器。然后,这些任务被移动到更细的时间轮上或被执行。插入(启动计时器)的成本是 O(m),其中 m 是时间轮的数量,通常与系统中的请求数量相比非常小,而删除(停止计时器)的成本仍然是 O(1)。

Doubly linked list for buckets in timing wheels

Hutool的实现在时间轮中使用双向链表来表示桶 ,我们为时间轮中的桶使用自己实现的双向链表。当一个计时任务实例被加入到计时队列时,它会在自身保存一个链接单元(link cell )。当任务完成或取消时,使用任务本身保存的链接单元来更新列表。双向链表的优势在于,如果我们可以访问列表中的链接单元,它允许 O(1) 时间复杂度内插入/删除列表项。

  • 11
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

well-done

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值