这里主要说的定时器的两个实现原理,定时器是如何能够及时高效的处理任务的,是如何在定时时间到了就去执行相对应的任务的,主要是是基于两种方法:一是基于有优先级队列的,二是基于时间轮的;
如果不是基于这两种结构的定时器的实现发现就会出现一下情况:要一直去遍历所有的定时器,检查当前的定时器是否已经到了任务的执行时间,如果是,就去执行任务,如果不是就去检查下一个定时器,这样看来好像没有什么问题,但是仔细一想,如果任务一多起来,检查的时间势必就很长,就一定有任务因为已经过期了,还没有被处理到,所以这样通过遍历来执行定时器是行不通的;所以有两种优秀的定时器机制更大家分享一下 :
1、基于优先级队列的定时器
我们都知道优先级队列可以根据比较器的不同来实现不同的优先级队列,可以根据时间的先后,值的大小等等顺序来实现不同顺序的优先级,基本可以分为两类,大根堆和小根堆,大根堆就是堆顶的值是最大的,小根堆就是堆顶的指是最小的,不过堆的排序是可以改变,重新排序的方法就可以根据你想要的将队列的元素进行排序,你可以根据字典序,可以根据大小,根据你自己想要的重写方法即可;
然而基于优先级队列的定时器就是根据定时的时间先后来排序的,时间越早就排越前面,越后的就排越后面,这样一来我们只要检查堆顶也就是根节点的定时器就可以,因为如果当前节点还没有到要执行的时间,那么后面的任务就一定还没有到执行的时间;但是我们也不是每时每刻都去检查堆顶的元素,我们只要根据堆顶元素定时时间和当前时间的差值来定一个时间,等到定时时间结束,我们再去检查堆顶元素是否要删除掉即可;
那如果在这个等待的过程中,有更早的定时任务要怎么办呢?检查堆顶元素的时间要怎么设定呢?其实只要在将该元素插入到队列的时候,由于该元素是比原来的堆顶元素更小的,所以他会代替堆顶元素,成为新的堆顶元素,这个时候我们只要再根据新的堆顶元素的定时时间和当前时间的差值重置一个下一次去检查堆顶元素的时间即可;
至于队列的定时器如何排序,如何删除,新的定时器如何插入到队列中,这就设计到优先级队列的原理,有兴趣的UU可以自行学习;原理是一致的,只不过队列的元素换成了定时器;
2、基于时间轮的定时器
大致的简图就是如上图所示:解释几个概念,会根据当前的任务的多少以及每个任务的定时的单位,比如秒或者毫秒,来划分成多个时间片段以及一个时间片段代表的时间间隔,比如图中是划分成八个,每个代表100ms;
那怎么添加元素到到时间轮中,又是依据什么划分的的呢,比如当前所检查的时间片为箭头所指的位置,且当前加入一个过期时间为300ms的任务,那么就会在当前的箭头往后顺移三个时间片,如图中的标号为1的位置所指向的链表中添加该任务;如果是过期时间为1秒的,那就要顺移10个时间片,也就是走了一圈了之后还得移动两个时间片;
所箭头所代表的就是当前检查的是那个时间片的链表上的任务,当箭头走到这个位置之后就会去检查上面的任务是否到了过期时间,如果到了就会去执行该任务;当前时间片的所有任务都执行完之后就去按照走到下一个时间片去检查,以此类推,每隔100ms就走到下一个时间片;
按照这样的模式去遍历每一个任务,就能够保证不重不漏的检查每个任务是否到了过期时间,且能够准时的释放内存,是一个高效且实用的方法;
值得注意的是:时间片的多少以及检查下一个时间片之间的时间间隔是要根据所有的任务来划分的,不是一味的按照一个方式,要根据实际情况来,如果一个任务只有20ms,那你按照100ms来划分就不适合,也划分不了。

被折叠的 条评论
为什么被折叠?



