java Timer和TimerTask实现定时任务和周期任务

是什么?为什么?怎么做?

一、是什么

Timer是一个工具类,用于安排以后在后台线程中执行的任务。

Timer可以安排任务执行一次,或者定期重复执行。可以将其看成一个定时器,可以调度TimerTask。TimerTask是Runnable接口的一个实现类,所以可以作为线程实现并发。

一个Timer可以调度任意多个TimerTask,它会将TimerTask存储在一个队列中,顺序调度。所以,如果想两个TimerTask并发执行,则需要创建两个Timer。

二、为什么

1.定时任务和周期任务

定时任务是比较常见的场景,例如:启动一条线程,同时启动一个延时任务监视线程的执行状况。如果超过一段时间线程仍未执行完,延时任务可以将其中断。

周期任务也是比较常见的场景,例如:监控数据库的状态,每隔一段时间就要执行sql/脚本获取数据库的各项参数。如果数据库关闭了,监控也可以随之关闭,取消周期任务。

2.如果使用thread,如何实现以上的情景?

定时任务似乎比较好实现,只要开启一条线程,sleep足够的时间,在规定的时间点运行即可。

周期任务就麻烦一些,可能需要两条线程。我个人认为分了两种情况:一种是任务马上执行,然后等待一段时间,再重新执行;另一种是先等待一段时间,执行任务,然后再等待一段时间。对于第一种情况,线程一马上执行,sleep足够的时间,唤醒线程二。线程二马上执行,sleep足够的时间,唤醒线程一。对于第二种情况,线程一sleep足够的时间,执行,唤醒线程二,线程二sleep足够的时间,执行,唤醒线程一。这两种方法实现的都是一个环状的结构。

无论是定时任务还是周期任务,每次都手动实现太麻烦了。这就是使用timer的原因。

三、怎么做

1.延时任务

(1)简单的延时任务

这里需要说明一个奇怪的现象,task线程作为一个timeTask,执行完之后,timer已经没有timeTask了,程序应该结束了才对。但是事实上,程序会继续运行一段时间。

查了一下之后,发现一篇文章:https://www.douban.com/note/64661564/

文中作者查了jdk的文档,发现在jdk1.5文档的Timer类中,有这样一句话:

“对Timer对象最后的引用完成后,并且所有未处理的任务都已执行完成后,计时器的任务执行线程会正常终止(并且成为垃圾回收的对象)。但是这可能要很长时间后才发生。”

作者同时提出了一个解决方法,加上System.gc方法,建议jvm回收Timer对象。

在我看来,这种方式应该是没有用的,System.gc不带有强制性,jvm理不理睬你还不一定呢。之后试了一下,果然一点用都没有。最后我想通了:操心这么多事干嘛呢,反正不会引起什么问题,干脆就不要管这个Timer什么时候结束,什么时候被回收。

(2)复杂一点的延时任务

添加了线程的超时处理。

2.周期任务

(1)简单的周期任务

简单的周期任务。

(2)复杂一点的周期任务

timeTask执行一定次数之后自行取消周期任务。

四、总结

为ScheduledThreadPoolExecutor做个铺垫。

发表评论

电子邮件地址不会被公开。 必填项已用*标注