首页 > 作文

java 计时器怎么用(java实现定时器的方式)

更新时间:2023-04-05 23:12:39 阅读: 评论:0

java在1.3版本引入了timer工具类,它是一个古老的定时器,搭配timertask和taskqueue一起使用。从java5开始在并发包中引入了另一个定时器
scheduledthreadpoolexecutor,它对timer做了很多改进并提供了更多的工具,可以认为是对timer的取代。

那为什么还要介绍timer工具类呢?通过了解timer的功能和它背后的原理,有助于我们更好的对比了解
scheduledthreadpoolexecutor,同时scheduledthreadpoolexecutor的一些改进思想在我们平时的编码工作中也可以借鉴。

主要成员变量

timer中用到的主要是两个成员变量:

taskqueue:一个按照时间优先排序的队列,这里的时间是每个定时任务下一次执行的毫秒数(相对于1970年1月1日而言)timerthread:对taskqueue里面的定时任务进行编排和触发执行,它是一个内部无限循环的线程。
//根据时间进行优先排序的队列    private final taskqueue q伞的英语ueue = new taskqueue();//消费线程,对queue中的定时任务进行编排和执行private final timerthread thread = new timerthread(queue);//构造函数public timer(string name) {        thread.tname(name);        thread.start();}

定时功能

timer提供了三种定时模式:

一次性任务按照固定的延迟执行(fixed delay)按照固定的周期执行(fixed rate)

第一种比较好理解,即任务只执行一次;针对第一种,timer提供了以下两个方法:

//在当前时间往后delay个毫秒开始执行public void schedule(timertask task, long delay) {...}//在指定的time时间点执行public void schedule(timertask task, date time) {...}

第二种fixed delay模式也提供了以下两个方法

//从当前时间开始delay个毫秒数开始定期执行,周期是period个毫秒数public void schedule(timertask task, long delay, long period) {...}////从指定的firsttime开始定期执行,往后每次执行的周期是period个毫秒数public void schedule(timertask task, date firsttime, long period){...}

它的工作方式是:

第一次执行的时间将按照指定的时cos15度间点执行(如果此时timerthread不在执行其他任务),如有其他任务在执行,那就需要等到其他任务执行完成才能执行。

从第二次开始,每次任务的执行时间是上一次任务开始执行的时间加上指定的period毫秒数。

如何理解呢,我们还是看代码

public static void main(string[] args) {        timertask task1 = new demotimertask("task1");        timertask task2 = new demotimertask("task2");        timer timer = new timer();        timer.schedule(task1, 1000, 5000);        timer.schedule(task2, 1000, 5000);}    static class demotimertask extends timertask {        private string taskname;        private dateformat df = new simpledateformat("hh:mm:ss---");                public demotimertask(string taskname) {            this.taskname = taskname;        }                @override        public void run() {            system.out.println(df.format(new date()) + taskname + " is working.");            try {                thread.sleep(2000);            } catch (interruptedexception e) {                // todo auto-generated catch block                e.printstacktrace();            }            system.out.println(df.format(new date()) + taskname + " finished work.");        }}

task1和task2是几乎同时执行的两个任务,而且执行时长都是2秒钟,如果此时我们把第六行注掉不执行,我们将得到如下结果(和第三种fixed rate模式结果相同):

13:42:58---task1 is working.13:43:00---task1 finished work.13:43:03---task1 is working.13:43:05---task1 finished work.13:43:08---task1 is working.13:43:10---task1 finished work.

如果打开第六行,我们再看下两个任务的执行情况。我们是期望两个任务能够同时执行,但是task2是在task1执行完成后才开始执行(原因是timerthread是单线程的,每个定时任务的执行也在该线程内完成,当多个任务同时需要执行时,只能是阻塞了),从而导致task2第二次执行的时间是它上一次执行的时间(13:43:57)加上5秒钟(13:44:02)。

13:43:55---task1 is working.13:43:57---task1 finished work.13:43:57---task2 is working.13:43:59---task2 finished work.13:44:00---task1 is working.13:44:02---task1 finished work.13:44:02---task2 is working.13:44:04---task2 finished work.

那如果此时还有个task3也是同样的时间点和间隔执行会怎么样呢?

结论是:也将依次排队,执行的时间依赖两个因素:

1.上次执行的时间

2.期望执行的时间点上有没有其他任务在执行,有则只能排队了

我们接下来看下第三种fixed r韵母声母ate模式,我们将上面的代码稍作修改:

public static void main(string[] args) {        timertask task1 = new demotimertask("task1");        timertask task2 = new demotimertask("task神话故事四年级2");                timer timer = new timer();        timer.scheduleatfixedrate(task1, 1000, 5000);        timer.scheduleatfixedrate(task2, 1000, 5000);}    static class demotimertask extends timertask {        private string taskname;        private dateformat df = new simpledateformat("hh:mm:s中医基础理论重点s---");                public demotimertask(string taskname) {            this.taskname = taskname;        }                @override        public void run() {            system.out.println(df.format(new date()) + taskname + " is working.");            try {                thread.sleep(2000);            } catch (interruptedexception e) {                // todo auto-generated catch block                e.printstacktrace();            }            system.out.println(df.format(new date()) + taskname + " finished work.");        }}

task1和task2还是在相同的时间点,按照相同的周期定时执行任务,我们期望task1能够每5秒定时执行任务,期望的时间点是:14:21:47-14:21:52-14:21:57-14:22:02-14:22:07,实际上它能够交替着定期执行,原因是task2也会定期执行,并且对taskqueue的锁他们是交替着拿的(这个在下面分析timerthread源码的时候会讲到)

14:21:47---task1 is working.14:21:49---task1 finished work.14:21:49---task2 is working.14:21:51---task2 finished work.14:21:52---task2 is working.14:21:54---task2 finished work.14:21:54---task1 is working.14:21:56---task1 finished work.14:21:57---task1 is working.14:21:59---task1 finished work.14:21:59---task2 is working.14:22:01---task2 finished work.

timerthread

上面我们主要讲了timer的一些主要源码及定时模式,下面我们来分析下支撑timer的定时任务线程timerthread。

timerthread大概流程图如下:

timerthread流程

源码解释如下:

private void mainloop() {        while (true) {            try {                timertask task;                boolean taskfired;                synchronized(queue) {                    // 如果queue里面没有要执行的任务,则挂起timerthread线程                    while (queue.impty() && newtasksmaybescheduled)                        queue.wait();                    // 如果timerthread被激活,queue里面还是没有任务,则介绍该线程的无限循环,不再接受新任务                    if (queue.impty())                        break;                     long currenttime, executiontime;                    // 获取queue队列里面下一个要执行的任务(根据时间排序,也就是接下来最近要执行的任务)                    task = queue.getmin();                    synchronized(task.lock) {                        if (task.state == timertask.cancelled) {                            queue.removemin();                            continue;  // no action required, poll queue again                        }                        currenttime = system.currenttimemillis();                        executiontime = task.nextexecutiontime;                        // taskfired表示是否需要立刻执行线程,当task的下次执行时间到达当前时间点时为true                        if (taskfired = (executiontime<=currenttime)) {                            //task.period==0表示这个任务只需要执行一次,这里就从queue里面删掉了                            if (task.period == 0) {                                 queue.removemin();                                task.state = timertask.executed;                            } el { // repeating task, reschedule                                //针对task.period不等于0的任务,则计算它的下次执行时间点                                //task.period<0表示是fixed delay模式的任务                                //task.period>0表示是fixed rate模式的任务                                queue.reschedulemin(                                  task.period<0 ? currenttime   - task.period                                                : executiontime + task.period);                            }                        }                    }                    // 如果任务的下次执行时间还没有到达,则挂起timerthread线程executiontime - currenttime毫秒数,到达执行时间点再自动激活                    if (!taskfired)                         queue.wait(executiontime - currenttime);                }                // 如果任务的下次执行时间到了,则执行任务                // 注意:这里任务执行没有另起线程,还是在timerthread线程执行的,所以当有任务在同时执行时会出现阻塞                if (taskfired)                      // 这里没有try catch异常,当timertask抛出异常会导致整个timerthread跳出循环,从而导致timer失效                    task.run();            } catch(interruptedexception e) {            }        }}

结论

通过上面的分析,我们可以得出以下结论:

timer支持三种模式的定时任务(一次性任务,fixed delay模式,fixed rate模式)timer中的timerthread是单线程模式,因此导致所有定时任务不能同时执行,可能会出现延迟timerthread中并没有处理好任务的异常,因此每个timertask的实现必须自己try catch防止异常抛出,导致timer整体失效

demo代码位置

本文发布于:2023-04-05 23:12:38,感谢您对本站的认可!

本文链接:https://www.wtabcd.cn/fanwen/zuowen/9ba422b0bf2afbc2b681617d7af76f94.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

本文word下载地址:java 计时器怎么用(java实现定时器的方式).doc

本文 PDF 下载地址:java 计时器怎么用(java实现定时器的方式).pdf

下一篇:返回列表
标签:时间   线程   模式   执行时间
相关文章
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2022 Comsenz Inc.Powered by © 专利检索| 网站地图