时间轮算法
TimerWheel实现 参考
KafkaHutoolHierarchical Timing Wheels
时间轮 是一种 实现延迟功能(定时器) 的 巧妙算法。 如果一个系统存在大量的任务调度,时间轮可以高效的利用线程资源来进行批量化调度。 把大批量的调度任务全部都绑定时间轮上,通过时间轮进行所有任务的管理,触发以及运行。 能够高效地管理各种延时任务,周期任务,通知任务等。
延时任务对比
- Timer、DelayQueue 和 ScheduledThreadPool,它们都是基于优先队列实现的,O(logn) 的时间复杂度
- 时间轮的实现类似钟表的运作方式,分层时间轮在正常情况, 它的任务插入和删除时间复杂度都为O(1)
SystemTimer
准确来说 时间轮是数据结构
时间轮+DelayQueue=定时器
DelayQueue是心脏,是动力
TimeWheel 构成
- tickMs(基本时间跨度):时间轮由多个时间格组成,每个时间格代表当前时间轮的基本时间跨度(tickMs)。
- wheelSize(时间单位个数):时间轮的时间格个数是固定的,可用(wheelSize)来表示, 那么整个时间轮的总体时间跨度(interval)可以通过公式 tickMs × wheelSize计算得出。
- currentTime(当前所处时间):时间轮还有一个表盘指针(currentTime),用来表示时间轮当前所处的时间, currentTime 是 tickMs 的整数倍。currentTime 可以将整个时间轮划分为到期部分和未到期部分, currentTime 当前指向的时间格也属于到期部分,表示刚好到期,需要处理此时间格所对应的 TimerTaskList 的所有任务。
- overflowWheel (上级时间轮)
- buckets 数组中的每个元素可以存放一个定时任务列表(TimerTaskList)。 TimerTaskList 是一个环形的双向链表,链表中的每一项表示的都是定时任务项(TimerTaskEntry),其中封装了真正的定时任务 TimerTask。
TimerWheel Add流程
- 首先在最小的
TimerWheel执行Add - 检查任务是否取消,是否已过期,若是,结束
- 检查此任务是不是在
interval内,若大于interval,到当前TimerWheel的overflowWheel执行Add方法 - 如果是是在
interval内,加入此TimerWheel。检查加入的桶(TimerTaskList)是不是新创建的,如果是加入DelayQueue中 - 因为同一个
TimerTaskList都是要同时处理的。
TimerWheel 推进时间流程
- 从
DelayQueue中获取一个TimerTaskList - 更新
TimerWheel的currentTime - 遍历
TimerTaskList,每个元素TimerTask 在最小的TimerWheel执行Add这一步是因为这个TimerTask是在原来的TimerWheel到期了,而不是要执行了 - 如果最小的
TimerWheel执行Add返回false,说明真的要执行了,扔给线程池执行.