Timer和TimerTask详解
1.概览
Timer是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次。
TimerTask一个抽象类,它的子类代表一个可以被Timer计划的任务。
简单的一个例程:
| import java.util.Timer; import java.util.TimerTask; /** public class Reminder { public Reminder(int seconds) { class RemindTask extends TimerTask { public static void main(String args[]) { |
运行这个小例子,你会首先看到:
About to schedule task.
5秒钟之后你会看到:
Time's up!
这个小例子可以说明一些用Timer线程实现和计划执行一个任务的基础步骤:
- 实现自定义的TimerTask的子类,run方法包含要执行的任务代码,在这个例子里,这个子类就是RemindTask。
- 实例化Timer类,创建计时器后台线程。
- 实例化任务对象 (
new RemindTask()). - 制定执行计划。这里用schedule方法,第一个参数是TimerTask对象,第二个参数表示开始执行前的延时时间(单位是milliseconds,这里定义了5000)。还有一种方法可以指定任务的执行时间,如下例,指定任务在11:01 p.m.执行:
| //Get the Date corresponding to 11:01:00 pm today. Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 1); calendar.set(Calendar.SECOND, 0); Date time = calendar.getTime(); timer = new Timer(); |
2.终止Timer线程
默认情况下,只要一个程序的timer线程在运行,那么这个程序就会保持运行。当然,你可以通过以下四种方法终止一个timer线程:
- 调用timer的cancle方法。你可以从程序的任何地方调用此方法,甚至在一个timer task的run方法里。
- 让timer线程成为一个daemon线程(可以在创建timer时使用new Timer(true)达到这个目地),这样当程序只有daemon线程的时候,它就会自动终止运行。
- 当timer相关的所有task执行完毕以后,删除所有此timer对象的引用(置成null),这样timer线程也会终止。
- 调用System.exit方法,使整个程序(所有线程)终止。
Reminder的例子使用了第一种方式。在这里不能使用第二种方式,因为这里需要程序保持运行直到timer的任务执行完成,如果设成daemon,那么当main线程结束的时候,程序只剩下timer这个daemon线程,于是程序不会等timer线程执行task就终止了。
有些时候,程序的终止与否并不只与timer线程有关。举个例子,如果我们使用AWT来beep,那么AWT会自动创建一个非daemon线程来保持程序的运行。下面的代码我们对Reminder做了修改,加入了beeping功能,于是我们需要加入System.exit的调用来终止程序。
| import java.util.Timer; import java.util.TimerTask; import java.awt.Toolkit; /** public class ReminderBeep { public ReminderBeep(int seconds) { class RemindTask extends TimerTask { public static void main(String args[]) { |
3.反复执行一个任务
先看一个例子:
| public class AnnoyingBeep { Toolkit toolkit; Timer timer; public AnnoyingBeep() { class RemindTask extends TimerTask { public void run() { |
执行,你会看到如下输出:
Task scheduled.
Beep!
Beep! //one second after the first beep
Beep! //one second after the second beep
Time's up! //one second after the third beep
这里使用了三个参数的schedule方法用来指定task每隔一秒执行一次。如下所列为所有Timer类用来制定计划反复执行task的方法 :
schedule(TimerTask task, long delay, long period)schedule(TimerTask task, Date time, long period)scheduleAtFixedRate(TimerTask task, long delay, long period)scheduleAtFixedRate(TimerTask task, Date firstTime, long period)
当计划反复执行的任务时,如果你注重任务执行的平滑度,那么请使用schedule方法,如果你在乎的是任务的执行频度那么使用scheduleAtFixedRate方法。 例如,这里使用了schedule方法,这就意味着所有beep之间的时间间隔至少为1秒,也就是说,如果有一个beap因为某种原因迟到了(未按计划执行),那么余下的所有beep都要延时执行。如果我们想让这个程序正好在3秒以后终止,无论哪一个beep因为什么原因被延时,那么我们需要使用scheduleAtFixedRate方法,这样当第一个beep迟到时,那么后面的beep就会以最快的速度紧密执行(最大限度的压缩间隔时间)。
4.进一步分析schedule和scheduleAtFixedRate
(1)2个参数的schedule在制定任务计划时, 如果指定的计划执行时间scheduledExecutionTime<=systemCurrentTime,则task会被立即执行。scheduledExecutionTime不会因为某一个task的过度执行而改变。
(2)3个参数的schedule在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间随着前一次的实际执行时间而变,也就是scheduledExecutionTime(第n+1次)=realExecutionTime(第n次)+periodTime。也就是说如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>=scheduledExecutionTime(第n+1次),则此时不做时隔等待,立即执行第n+1次task,而接下来的第n+2次task的scheduledExecutionTime(第n+2次)就随着变成了realExecutionTime(第n+1次)+periodTime。说白了,这个方法更注重保持间隔时间的稳定。
(3)3个参数的scheduleAtFixedRate在制定反复执行一个task的计划时,每一次执行这个task的计划执行时间在最初就被定下来了,也就是scheduledExecutionTime(第n次)=firstExecuteTime+n*periodTime;如果第n次执行task时,由于某种原因这次执行时间过长,执行完后的systemCurrentTime>=scheduledExecutionTime(第n+1次),则此时不做period间隔等待,立即执行第n+1次task,而接下来的第n+2次的task的scheduledExecutionTime(第n+2次)依然还是firstExecuteTime+(n+2)*periodTime这在第一次执行task就定下来了。说白了,这个方法更注重保持执行频率的稳定。
5.一些注意的问题
- 每一个Timer仅对应唯一一个线程。
- Timer不保证任务执行的十分精确。
- Timer类的线程安全的。
Timer和TimerTask详解的更多相关文章
- JDK中的Timer和TimerTask详解(zhuan)
http://www.cnblogs.com/lingiu/p/3782813.html ************************************************** 目录结构 ...
- JDK中的Timer和TimerTask详解
http://www.cnblogs.com/lingiu/p/3782813.html
- 【eclipse插件开发实战】 Eclipse插件开发5——时间插件Timer开发实例详解
Eclipse插件开发5--时间插件Timer开发实例详解 这里做的TimeHelper插件设定为在菜单栏.工具栏提供快捷方式,需要在相应地方设置扩展点,最后弹出窗体显示时间. 在上一篇文章里创建好了 ...
- Java定时器Timer使用方法详解
感谢大佬:https://www.jb51.net/article/129808.htm 一.概念 定时计划任务功能在Java中主要使用的就是Timer对象,它在内部使用多线程的方式进行处理,所以它和 ...
- Java定时器Timer的使用详解
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6374714.html 定时器在Web开发中使用得不是很多.这里主要列举一下使用定时器的步骤,方便日后使用时查 ...
- .NET中的Timer类型用法详解
这篇文章主要介绍了.NET中的Timer类型用法,较为详细的分析了Timer类型在各种环境下的用法,需要的朋友可以参考下 在.NET FrameWork中有多个Timer,那么怎么根据实际情况进行 ...
- Java定时任务Timer、TimerTask与ScheduledThreadPoolExecutor详解
定时任务就是在指定时间执行程序,或周期性执行计划任务.Java中实现定时任务的方法有很多,本文从从JDK自带的一些方法来实现定时任务的需求. 一.Timer和TimerTask Timer和Tim ...
- Java定时任务工具详解之Timer篇
Java定时任务调度工具详解 什么是定时任务调度? ◆ 基于给定的时间点,给定的时间间隔或者给定的执行次数自动执行的任务. 在Java中的定时调度工具? ◆ Timer ◆Quartz T ...
- JAVA定时任务调度之Timer入门详解(一)
所谓的Timer,打开jdk的api文档可以看到它的定义:一种工具,线程用其安排以后在后台线程中执行的任务.可安排任务执行一次,或者定期重复执行.通俗点讲就是说:有且仅有一个后台线程对多个业务线程进行 ...
随机推荐
- 为什么要用mallloc
为什么要用malloc函数申请内存空间? 有的程序往往在运行时才知道要动态分配多大的内存,例如: void foo(char *str, int n) { char buf[?]; strncpy(b ...
- Outlook Web App 客户端超时设置
这篇文章我们讨论一下,OWA 2013在公共和私人的电脑是如何启用和配置. Exchange 2013 Outlook Web App (OWA) 登录页不再允许用户选择无论他们正在使用公共的或私人的 ...
- LoadRunner问题解决
1.问题:复制脚本,修改后并保存,直接在controller中加载脚本,无法创建用户,出现“Loadrunner Controller cannot create Vusers. Ensure th ...
- 安装新版REDIS
http://redis.io/ # wget http://download.redis.io/redis-stable.tar.gz tar zxvf redis-stable.tar.gz -C ...
- Mybatis学习记录(1)
1.Mybatis介绍 Mybatis是apache的一个开源项目iBatis,Mybatis是一个优秀的持久层框架,他对jdbc的操作数据库的过程进行封装,使开发者只需要关注sql本身,不需 ...
- TabControl重写,添加关闭按钮
class userTabControl : TabControl { const int CLOSE_SIZE = 15; protected override void OnInvalidated ...
- 洛谷P3372线段树1
难以平复鸡冻的心情,虽然可能在大佬眼里这是水题,但对蒟蒻的我来说这是个巨大的突破(谢谢我最亲爱的lp陪我写完,给我力量).网上关于线段树的题解都很玄学,包括李煜东的<算法竞赛进阶指南>中的 ...
- 【概率dp 高斯消元】bzoj3270: 博物馆
一类成环概率dp的操作模式 Description 有一天Petya和他的朋友Vasya在进行他们众多旅行中的一次旅行,他们决定去参观一座城堡博物馆.这座博物馆有着特别的样式.它包含由m条走廊连接的n ...
- 使用jquery清除select中的所有option
html代码 <select id="search"> <option>baidu</option> <option>sogou&l ...
- 设置mysql允许外部连接访问
错误信息: SQL Error (1130): Host ‘192.168.1.88’ is not allowed to connect to this MySQL server 说明所连接的用户帐 ...