unix下有cron程序来实现定时执行的功能,但cron的实现是每分钟被唤醒后检查一下,当前是否有需要执行的任务,这种实现方案当然很简单也很可靠,但看起来实在太笨,笔者这样自诩“聪明”的人就想换个更节省资源的方案来实现。
首先实现了一个任务队列,其每一个任务节点主要包括两个部分,一是节点秒数,意为从上一个节点到本节点的时间间隔;二是需执行的任务。
当需要设置某个时钟任务时:
1、将所有需要按时执行的任务和当前时间比较一下,得到其从现在开始多少秒后开始执行,称为S;
2、从任务队列的头一直向后搜索,对于每一个任务节点,首先比较S和节点秒数sn,如果sn<S,那么另S=S-sn,然后继续搜索下一个节点;
3、如果S==sn,那么就将该任务添加到当前任务节点的action中;
4、如果S<sn,那么就生成一个新的任务节点,另其节点秒数为S,然后将其插入到任务队列当前任务节点(sn)之前,同时修改当前任务节点的节点秒数sn=sn-S。
该任务队列每次触发后将头节点的节点秒数减一,即s0=s0-1,如果s0等于0那么就删除该头节点,同时异步执行其action。
有了这个任务队列,那么定时器就是计算出下一次应该执行的时间点,然后将其插入到任务队列中即可。所以cron功能就转换为依次取定时器的下一次触发的时间点。要实现根据指定的年月日时分的设置来确定下一个有效时间,如果没有合理的构造会比较麻烦,笔者将其抽象为5位的数字系统,这个数字系统的基础是5个不定进制数的串联,所谓的不定进制,就是说要打破我们平常所司空见惯的十进制、二进制的概念,而是将用户所指定的时间值作为进制基础,指定了几个数字就是几位,然后实现了这个不定进制数的加法系统,其实就是加一运算,溢出后归"0"并进一。举个例子来进行说明:
比如,我们想在每个月的1号、11号、21号、31号的5点、15点的9分执行某动作,那么这个数字系统的设置就是:
年:2011-3000所组成的990进制数,年位溢出则数字肯定无效;
月:1-12组成的12进制数;
日:1、11、21、31这四个数所组成的四进制数(即取值就是这四个数之一,而且1加一等于11、11加一等于21、21加一等于31、31加一等于1同时需向月位进一);
时:5、15所组成的两进制数(5加一等于15、15加一等于5同时需向日位进一);
分:9所组成的一进制数(9加一等于9同时向时位进一)。
那么,当用当前时间(如:2013-11-21 11:18:00)进行初始化后,得到:
年:2013
月:11
日:21
时:15
分:9
即下一次的执行时间是:2013-11-21 15:9:00,如果要获得再下一次的执行时间就将这个数字系统加一,得到:2013-11-31 5:9:00,但是11月没有31号,所以该值显然不合法,那么继续加一,得到:2013-11-31 15:9:00,还是不合法,继续加一,得:2013-12-1 5:9:00,合法。那么第二次的执行时间点就是2013-12-1 5:9:00。只要再结合是否需考虑星期就可以完全实现corn的功能了。
整个数字系统及其加法运算实现起来还是很容易的,只是需要突破我们常见的10进制、2进制所形成的固有概念和思维定式,希望能对大家有所启发。
JXBiz ORM平台编程简明参考手册 JXWork任务管理软件源代码