动手实现一个定时器

前言

很久没有写博客了,那是因为的确没有什么有意思的新知识可以拿来写写,感觉好像有点儿变懒了,倦怠了,没有之前那么有劲儿了,哎,可恶啊,这可是技术博客来着,你在这里抒发什么心情尼。好吧,其实也并不是一无所获,比如最近自己写着玩的任务定时器,就可以拿来水一篇博客的啊。

简介

事出有因,因为之前同事说他那边自己实现了一个时间轮,用于执行定时任务来着,就是kafka里边的timewheel,不过原版的时间轮是用来执行延时任务的(应该是一个类似于java.util.concurrent.DelayQueue的玩意儿),然后他让任务重入了一下队列,达到了一个定时执行的效果。不过之前我是不知道的,我还以为时间轮是个什么高大上的玩意儿尼,所以就准备自己实现一个定时器来着,然后就着手写了,大概花了一个周末的时间吧,第一版就出来了。
下面来说说我的设计吧。

设计

首先要明确的是我们需要设计一个定时器,也就是crontab这样的东东,由于收到 时间轮 这三个字的影响,脑海中就很自然的出现了一个钟表的模型,那种机械式的哦,大概长这个样🕙,有三层,秒针,分针和时针。秒针是一个推动器,推着分针转圈圈,当分针满了一圈后,进位,时针转圈圈,由于只有三层,所以时针满了一圈后,就会整体从头开始,可以在脑海中想像一下:23:59:59 --> 00:00:00的过程。
当我的一个任务丢进这个钟表后,首先会从最低层寻找,秒针盘60s,够不够用,这里的够不够用是指定时器的定时间隔,也就是没多久执行一次任务,如果不够就向上一层,看分针盘够不够用,分针盘是60格,每一个格就等于下一层的全部范围,也就是60s,所以分针盘就是60*60=3600s,而如果任务还放不下,那么就需要接着看时针盘符不符合要求了。一个逐层检查的过程。当找到一个合适的位置放下后,同时秒针是永远在走步的,取出每一层指针所在的格子的任务,降级,表示已经过了这么久任务下放到更底层的位置,而如果秒针盘,也即是最低一层,就直接取出任务并执行就好了,然后在把任务丢进去,按照相对时间丢进去。

举个栗子🌰

脑海中想象一个三层的钟表。

  • 项目刚启动,三层指针都是指在0,0,0的位置上。
  • 这时候丢进去一个定时1小时1分钟零1秒的任务,那么首先会将任务放在时针盘位置为1的格子中。
  • 然后秒针转啊转,分针转啊转
  • 指针转到1,0,0,时针终于进位了,到了1的位置
  • 这时候,取出这个时针盘中格子1中的任务,一看,还需要1分钟,因此,任务降级,放到分针盘中位置为1的格子位置上
  • 然后秒针转啊转,分针转啊转
  • 指针转到1,1,0,当分针指向1格的时候,从分针盘中取出任务,一看,还需要1秒钟,任务降级,放到秒针盘上位置为1的格子中。
  • 然后秒针转啊转,分针转啊转
  • 指针转到1,1,1,当秒针指向1的时候,取出任务,发现是最底层了,因此,直接执行。
  • 然后再放入时间轮中。这时候时间轮的指针是1,1,1,因此需要放到相对位置上,应该是2,2,2的位置上,然后以此往复。
    不知道爱思考的小伙伴想明白了吗,感觉还是蛮生动形象的吧,下面就是实践环节喽。

实践

纸上得来终觉浅,绝知此事要躬行。
这里贴出我的实现github地址吧,就不贴代码了。

思考

  • 精度。不知道小伙伴们主要到没有,时间精度是秒,如果想要更精确的定时,按照这个设计,可以实现一个毫秒精度,微秒精度的时间轮(纳秒感觉没意义了~~)
  • 其实如果是量不大,可以使用一个PriorityQueue,比较器是任务下一次执行时间,每次从queue头peek最快要执行的任务,判断是否到期,到期就取出执行,重置下一次执行时间,再丢回去,没到期就下一轮判断。这也就是java中timer的原理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值