目录

1 从定时任务说起

2 初识时间轮

3 绝对时间和相对时间

4 需要重复执行多次的任务

5 同一时刻存在多个任务

6 时间轮的数据结构

7 时间刻度不够用怎么办?

7.1 增大时间轮的刻度

7.2 列表中的任务中添加round属性——round时间轮

8 分层时间轮

9 round时间轮和分层时间轮的一点比较


1 从定时任务说起

自然界中定时任务无处不在,太阳每天东升西落,候鸟的迁徙,树木的年轮,人们每天按时上班,每个月按时发工资、交房租,四季轮换,潮涨潮落,等等,从某种意义上说,都可以认为是定时任务。
大概很少有人想过,这些“定时”是怎样做到的。当然,计算机领域的同学们可能对此比较熟悉,毕竟工作中的定时任务也是无处不在的:每天凌晨更新一波数据库,每天9点发一波邮件,每隔10秒钟抢一次火车票。。。
至于怎么实现的?很简单啊,操作系统的crontab,spring框架的quartz,实在不行Java自带的ScheduledThreadPool都可以很方便的做到定时任务的管理调度。
当你熟练的敲下“* * 9 * * ?”等着神奇的事情发生时,你是否想过背后的“玄机”?

2 初识时间轮

大概去年的时候,业务需要实现一个时间调度的工具,定时生成报表,同组的哥们儿想了一个取巧的办法:
1. 启动时从DB读取cron表达式解析,算出该任务下次执行的时间。
2. 下次执行的时间 - 当前时间 = 时间差。
3. 向ScheduleThreadPool线程池中提交一个延迟上面算出来的时间差的执行的任务。
4. 任务执行时,算一下这个任务下次执行的时间,算时间差,提交到线程池。
5. 当任务需要取消时,直接调用线程池返回的Future对象的cancel()方法就行了。
当时稍微想了一ScheduleThreadPool是怎么做到定时执行提交过来的任务的,大概有个模糊的概念,后来就把这事忘了。再后来,一次在地铁上看到一篇文章,讲了一种叫做时间轮的定时任务调度思想,感觉想法很不错,当年那个模糊的概念似乎清晰了很多,再后来,一个偶然的机会,网上搜了一下,竟然有一篇专门讲解时间轮算法的论文,顿时兴奋无比,赶紧打印下来,在上班的地铁上读了半个月,总算读完了。
戳这里下载:《Hashed and Hierarchical Timing Wheels》
论文中的思路很简单但也十分巧妙,对算法不断的改进对比,各种操作系统,框架中的基于时间的调度算法都是基于时间轮的思想实现的。下面我们来看看,这个神奇的时间轮到底是怎样实现定时任务的调度的。

3 绝对时间和相对时间

定时任务一般有两种:
1. 约定一段时间后执行。
2. 约定某个时间点执行。
聪明的你会很快发现,这两者之间可以相互转换,比如给你个任务,要求12点执行,你看了一眼时间,发现现在是9点钟,那么你可以认为这个任务三个小时候执行。
同样的,给你个任务让你3个小时后执行,你看了一眼现在是9点钟,那么你当然可以认为这个任务12点钟执行。
我们先来考虑一个简单的情况,你接到三个任务A、B、C(都转换成绝对时间),分别需要再3点钟,4点钟和9点钟执行,正当百思不得其解时,不经意间你瞅了一眼墙上的钟表,瞬间来了灵感,如醍醐灌顶,茅塞顿开:

如上图中所示,**我只需要把任务放到它需要被执行的时刻,然后等着时针转到这个时刻时,取出该时刻放置的任务,执行就可以了**。 这就是时间轮算法最核心的思想了。 什么?时针怎么转? while-true-sleep 下面让我们一点一点增加复杂度。

4 需要重复执行多次的任务

多数定时任务是需要重复执行,比如每天上午9点执行生成报表的任务。对于重复执行的任务,其实我们需要关心的只是下次执行时间,并不关心这个任务需要循环多少次,还是那每天上午9点的这个任务来说。
1. 比如现在是下午4点钟,我把这个任务加入到时间轮,并设定当时针转到明天上午九点(该任务下次执行的时间)时执行。
2. 时间来到了第二天上午九点,时间轮也转到了9点钟的位置,发现该位置有一个生成报表的任务,拿出来执行。
3. 同时时间轮发现这是一个循环执行的任务,于是把该任务重新放回到9点钟的位置。
4. 重复步骤2和步骤3。
如果哪一天这个任务不需要再执行了,那么直接通知时间轮,找到这个任务的位置删除掉就可以了。
由上面的过程我们可以看到,时间轮至少需要提供4个功能:
1. 加入任务
2. 执行任务
3. 删除任务
4. 沿着时间刻度前进

5 同一时刻存在多个任务

上面说的是同一个时刻只有一个任务需要执行的情况,更通用的情况显然是同一时刻可能需要执行多个任务,比如每天上午九点除了生成报表之外,还需要执行发送邮件的任务,需要执行创建文件的任务,还需执行数据分析的任务等等,于是你刚才可能就比较好奇的时间轮的数据结构到现在可能更加好奇了,那我们先来说说时间轮的数据结构吧。

6 时间轮的数据结构

首先,时钟可以用数组或者循环链表表示,这个每个时钟的刻度就是一个槽,槽用来存放该刻度需要执行的任务,如果有多个任务需要执行呢?每个槽里面放一个链表就可以了,就像下面图中这样:

同一时刻存在多个任务时,只要把该刻度对应的链表全部遍历一遍,执行(扔到线程池中异步执行)其中的任务即可。

7 时间刻度不够用怎么办?

如果任务不只限定在一天之内呢?比如我有个任务,需要每周一上午九点执行,我还有另一个任务,需要每周三的上午九点执行。一种很容易想到的解决办法是:

7.1 增大时间轮的刻度

一天24个小时,一周168个小时,为了解决上面的问题,我可以把时间轮的刻度(槽)从12个增加到168个,比如现在是星期二上午10点钟,那么下周一上午九点就是时间轮的第9个刻度,这周三上午九点就是时间轮的第57个刻度,示意图如下:

仔细思考一下,会发现这中方式存在几个缺陷:
1. 时间刻度太多会导致时间轮走到的多数刻度没有任务执行,比如一个月就2个任务,我得移动720次,其中718次是无用功。
2. 时间刻度太多会导致存储空间变大,利用率变低,比如一个月就2个任务,我得需要大小是720的数组,如果我的执行时间的粒度精确到秒,那就更恐怖了。
于是乎,聪明的你脑袋一转,想到另一个办法:

7.2 列表中的任务中添加round属性——round时间轮

这次我不增加时间轮的刻度了,刻度还是24个,现在有三个任务需要执行,
1. 任务一每周二上午九点。
2. 任务二每周四上午九点。
3. 任务三每个月12号上午九点。
比如现在是9月11号星期二上午10点,时间轮转一圈是24小时,到任务一下次执行(下周二上午九点),需要时间轮转过6圈后,到第7圈的第9个刻度开始执行。
任务二下次执行第3圈的第9个刻度,任务三是第2圈的第9个刻度。
示意图如下:

时间轮每移动到一个刻度时,遍历任务列表,把round值-1,然后取出所有round=0的任务执行,若是重复任务,执行完后将round恢复到最初值,再将任务重新放入时间轮中。 这样做能解决时间轮刻度范围过大造成的空间浪费,但是却带来了另一个问题:时间轮每次都需要遍历任务列表,耗时增加,当时间轮刻度粒度很小(秒级甚至毫秒级),任务列表又特别长时,这种遍历的办法是不可接受的。 当然,对于大多数场景,这种方法还是适用的。 有没有既节省空间,又节省时间的办法呢?答案是有的,正如《Hashed and Hierarchical Timing Wheels》标题中提到的,有一种分层时间轮,可以解决做到既节省空间,又节省时间:

8 分层时间轮

分层时间轮是这样一种思想:
1. 针对时间复杂度的问题:不做遍历计算round,凡是任务列表中的都应该是应该被执行的,直接全部取出来执行。
2. 针对空间复杂度的问题:分层,每个时间粒度对应一个时间轮,多个时间轮之间进行级联协作。
第一点很好理解,第二点有必要举个例子来说明:
比如我有三个任务:
1. 任务一每周二上午九点。
2. 任务二每周四上午九点。
3. 任务三每个月12号上午九点。
三个任务涉及到四个时间单位:小时、天、星期、月份。
拿任务三来说,任务三得到执行的前提是,时间刻度先得来到12号这一天,然后才需要关注其更细一级的时间单位:上午9点。
基于这个思想,我们可以设置三个时间轮:月轮、周轮、天轮。
月轮的时间刻度是天。
周轮的时间刻度是天。
天轮的时间刻度是小时。
初始添加任务时,任务一添加到天轮上,任务二添加到周轮上,任务三添加到月轮上。
三个时间轮以各自的时间刻度不停流转。
当周轮移动到刻度2(星期二)时,取出这个刻度下的任务,丢到天轮上,天轮接管该任务,到9点执行。
同理,当月轮移动到刻度12(12号)时,取出这个刻度下的任务,丢到天轮上,天轮接管该任务,到9点执行。
这样就可以做到既不浪费空间,有不浪费时间。
整体的示意图如下所示:

9 round时间轮和分层时间轮的一点比较

相比于round时间轮思想,采用分层时间轮算法的优点在于:只需要多耗费极少的空间(从1个时间轮到3个时间轮),就能实现多线程在效率上的提高(一个时间轮是一个线程去行走,3个时间轮可以3个线程行走)。当然这是相对的,若提交的任务都是每隔几个小时重复执行,那显然小时时间轮比月、周、小时时间轮组合的耗费空间少,且执行时间还相同。

##时间轮的应用
时间轮的思想应用范围非常广泛,各种操作系统的定时任务调度,Crontab,还有基于java的通信框架Netty中也有时间轮的实现,几乎所有的时间任务调度系统采用的都是时间轮的思想。
至于采用round型的时间轮还是采用分层时间轮,看实际需要吧,时间复杂度和实现复杂度的取舍。

【定时任务】时间轮算法相关推荐

  1. .Net之时间轮算法(终极版)定时任务

    TimeWheelDemo 一个基于时间轮原理的定时任务 对时间轮的理解 其实我是有一篇文章(.Net 之时间轮算法(终极版)[1])针对时间轮的理论理解的,但是,我想,为啥我看完时间轮原理后,会采用 ...

  2. 从 Kafka 看时间轮算法设计

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://juejin.cn/post/7047405443961847816 前言 Kafka 中有很多延时操作,比如 ...

  3. java 时间轮算法_时间轮算法(TimingWheel)是如何实现的?

    前言 我在2. SOFAJRaft源码分析-JRaft的定时任务调度器是怎么做的?这篇文章里已经讲解过时间轮算法在JRaft中是怎么应用的,但是我感觉我并没有讲解清楚这个东西,导致看了这篇文章依然和没 ...

  4. 原 荐 简单说说Kafka中的时间轮算法

    零.时间轮定义简单说说时间轮吧,它是一个高效的延时队列,或者说定时器.实际上现在网上对于时间轮算法的解释很多,定义也很全,这里引用一下 朱小厮博客 里出现的定义:参考下图,Kafka中的时间轮(Tim ...

  5. 时间轮算法解析(Netty HashedWheelTimer源码解读)

    1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...

  6. 心跳超时时间设置_定时器实现之时间轮算法

    前言 在看这篇文章的时候对其中超时控制一块儿有点好奇.通过时间轮来控制超时?啥是时间轮?怎么控制的?文章会先介绍常见的计时超时处理,再引入时间轮介绍及 netty 在实现时的一些细节,最后总结下实现的 ...

  7. java 时间轮算法_时间轮算法解析(Netty HashedWheelTimer源码解读)

    1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...

  8. TimeWheel时间轮算法原理及实现(附源码)

    时间轮算法原理及实现 前言 1.时间轮核心 2.简单定时器 3.任务队列 4.优化任务队列 5.简单时间轮 6.多层时间轮 前言  在各种业务场景中,我们总是会需要一些定时进行一些操作,这些操作可能是 ...

  9. 时间轮算法(TimingWheel)

    时间轮算法的应用非常广泛,在 Dubbo.Netty.Kafka.ZooKeeper.Quartz 的组件中都有时间轮思想的应用,甚至在 Linux 内核中都有用到. 其思想理论基础可以参考论文:ht ...

最新文章

  1. android手机内存这么大,专业解读:为什么安卓手机的内存越来越大?
  2. 像鸟一样树上栖息、空中抓物,斯坦福给无人机安上爪子,登Science子刊封面
  3. 线上分享 | 产品架构搭建:从业务到体系
  4. SecureCRT 或者 超级终端 始终无法ping通主机
  5. 想写Python爬虫?看这5个教程就行了!
  6. sklearn自学指南(part39)--Birch
  7. 如何将html特殊字符编码转换成特殊字符_html十进制编码字符转回来
  8. SUPERSET使用笔记
  9. 《C#高效编程》读书笔记11-理解短小方法的优势
  10. C++--第9课 - 构造与析构 - 上
  11. 拓端tecdat|R语言进行数据结构化转换:Box-Cox变换、“凸规则”变换方法
  12. Swift 5 Dictionary用法大全
  13. 【通俗理解】开漏/开集,线与
  14. 大数据Hadoop之——数据同步工具DataX
  15. px和毫米的换算_关于PX像素、PT点数、CM厘米、MM毫米之间的换算[转]
  16. 笔记本触摸板手势使用
  17. Pipeline支撑运维自动化:sftp原子模块
  18. 三星980处理器和骁龙855_手机处理器最新排名:麒麟980因一缺陷,不敌高通骁龙855...
  19. 推荐系统常用数据集介绍
  20. 【SwiftUI模块】0033、SwiftUI创建用户双击帖子时的心形动画

热门文章

  1. Lubuntu自动登录(修改配置文件)
  2. 二维数组赋值 java_java二维数组的赋值方法
  3. 形容计算机专业的诗句,形容信息技术的诗句
  4. 霞浦职业中专学校计算机专业,2019年霞浦职业中专学校中职中专招生简章
  5. 20181204 周二 日记
  6. 在线压缩图片网站源码
  7. 2023最新SSM计算机毕业设计选题大全(附源码+LW)之java社区智慧养老系统b0lh8
  8. 计算机在信息社会中主要的应用,计算机在信息社会中的应用ppt
  9. 《深入理解计算机系统》读书笔记(1)
  10. 计算机java毕业设计 SSM大学生在线兼职发布与管理平台