`
truelove12358
  • 浏览: 77709 次
  • 性别: Icon_minigender_1
  • 来自: 上海
文章分类
社区版块
存档分类
最新评论

Java:如何正确使用Timer

 
阅读更多



Java:如何正确使用Timer

在需要按时间计划执行简单任务的情况下,Timer是最常被使用到的工具类。使用Timer来调度TimerTask的实现者来执行任务,有两种方式,一种是使任务在指定时间被执行一次,另一种是从某一指定时间开始周期性地执行任务。

下面是一个简单的Timer例子,它每隔10秒钟执行一次特定操作doWork。
Timer timer = new Timer();
TimerTask task = new TimerTask (){
public void run() {
doWork();
}
};
timer.schedule (task, 10000L, 10000L);
可以看到,具体的任务由TimerTask的子类实现,Timer负责管理、执行TimerTask。

Timer 的使用
在不同的场景下,需要使用不同的Timer接口。如上所说,主要区分两种情况
1) 在指定时间执行任务,只执行一次
- public void schedule(TimerTask task, long delay)
- public void schedule(TimerTask task, Date time)

2)从指定时间开始,周期性地重复执行,直到任务被cancel掉。其中又分两种类型:
2.1) 一种是按上一次任务执行的时间为依据,计算本次执行时间,可以称为相对时间法。比如,如果第一次任务是1分10秒执行的,周期为5秒,因系统繁忙(比如垃 圾回收、虚拟内存切换),1分15秒没有得到机会执行,直到1分16秒才有机会执行第二次任务,那么第3次的执行时间将是1分21秒,偏移了1秒。
- public void schedule(TimerTask task, long delay, long period)
- public void schedule(TimerTask task, Date firstTime, long period)

2.2) 另一种是绝对时间法,以用户设计的起始时间为基准,第n次执行时间为“起始时间+n*周期时间”。比如,在上面的情况下,虽然因为系统繁忙,第二执行时间被推后1秒,但第3次的时间点仍然应该是1分20秒。
- public void scheduleAtFixedRate(TimerTask task, long delay, long period)
- public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period)

相 对时间法,关注于满足短时间内的执行间隔,绝对时间法,则更关注在一个长时间范围内,任务被执行的次数。如果我们要编写一个程序,用timer控制文档编 辑器中提示光标的闪烁,用哪种更合适? 当然是相对时间法。如果改用绝对时间法,当从系统繁忙状态恢复后,光标会快速连续闪烁多次,以弥补回在系统繁忙期间没有被执行的任务,这样的情况会用户来 说比较难以接受。又如,每10分钟检查一次新邮件的到来,也适合于使用相对时间法。
Timer timer = new Timer();
TimerTask task = new TimerTask (){
public void run() {
displayCursor();
}
};
timer.schedule (task, 1000L, 1000L); //每秒闪烁一次光标

作为对比,我们来考虑一种绝对时间法的应用场景——倒数任务,比如,要求在10秒内做倒数计时,每秒做一次doworkPerSecond操作,10秒结束时做一次doworkEnd操作,然后结束任务。
Timer timer = new Timer();
TimerTask task = new TimerTask (){
private int count=10;
public void run() {
if(count>0){
doWorkPerSecond();
count--;
}else{
doWorkEnd();
cancel();
}
}
};
timer. scheduleAtFixedRate (task, 1000L, 1000L);
Timer及相关类的内部实现
Timer的内部会启动一个线程TimerThread。即使有多个任务被加入这个Timer,它始终只有一个线程来管理这些任务。
- TimerThread是Thread的子类。加入Timer的所有任务都会被最终放入TimerThread所管理的TaskQueue中。 TimerThread会不断查看TaskQueue中的任务,取出当前时刻应该被执行的任务执行之,并且会重新计算该任务的下一次执行时间,重新放入 TaskQueue。直到所有任务执行完毕(单次任务)或者被cancel(重复执行的任务),该线程才会结束。
- TaskQueue,由数组实现的二叉堆,堆的排序是以任务的下一次执行时间为依据的。二叉堆的使用使得TimerThread以简洁高效的方式快速找到 当前时刻需要执行的TimerTask,因为,堆排序的特性是保证最小(或者最大)值位于堆叠顶端,在这里,queue[1]始终是下次执行时间 (nextExecutionTime)最小的,即应该最先被执行的任务

比如,同一个timer管理两个任务task1和task2
timer.schedule (task1, 4000L, 10000L);
timer. scheduleAtFixedRate (task2, 2000L, 15000L);
则,TaskQueue 中会有两个任务:task1和task2。task2会排在头部queue[1],当task2执行时间到,task2被执行,同时修改其 nextExecutionTime =当前的nextExecutionTime +15000L(绝对时间法)并重新在二叉堆中排序。排序后,task1被放到头部。当task1执行时间到,task1被执行,并修改其 nextExecutionTime =当前时间+10000L,然后重新在二叉堆中对其排序………

一个例子
当收到客户端请求时,服务端生成一个Response对象。服务端希望客户端访问该对象的间隔时间不能超过20秒,否则,服务端认为客户端已经异常关闭或者网络异常,此时销毁掉该对象并打印错误日志。每次访问都会重新开始计时。

class Response{
private TimerTask timeout;
public void init(){
………
Timer timer = new Timer();
timeout = new TimeOutTask();
timer.schedule (timeout, 20000L);
}

public void invoke(){
timeout.cancel();//取消当前的timeout任务
; ….
timeout = new TimeOutTask();
timer.schedule (timeout, 20000L);//重新开始计时
}

void destroy(){
……..
}

class TimeOutTask extends TimerTask{
public void run() {
TraceTool.error(“Time out, destroy the Response object.”);
destroy();
}
}
}

因为Timer不支持对任务重置计时,所以此处采取了先cancel当前的任务再重新加入新任务来达到重置计时的目的。注意,对一个已经cancel的任务,不能通过schedule重新加入Timer中执行。TimerTask的状态机如下:

一个新生成的TimerTask其状态为VIRGIN,Timer只接受状态为VIRGIN的任务,否则会有IllegalStateException异常抛出。
调用任务的cancel方法,该任务就转入CANCELLED状态,并很快从TaskQueue中删除。对单次执行的任务,一旦执行结束,该任务也会从中删除。这意味着TimerTask将不再被timer所执行了。


va实现定时任务的三种方法

  在应用里经常都有用到在后台跑定时任务的需求。举个例子,比如需要在服务后台跑一个定时任务来进行非实时计算,清除临时数据、文件等。在本文里,我会给大家介绍3种不同的实现方法:
  • 普通thread实现
  • TimerTask实现
  • ScheduledExecutorService实现

普通thread

这是最常见的,创建一个thread,然后让它在while循环里一直运行着,通过sleep方法来达到定时任务的效果。这样可以快速简单的实现,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
publicclassTask1 {
publicstaticvoidmain(String[] args) {
// run in a second
finallongtimeInterval =1000;
Runnable runnable =newRunnable() {
publicvoidrun() {
while(true) {
// ------- code for task to run
System.out.println("Hello !!");
// ------- ends here
try{
Thread.sleep(timeInterval);
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
};
Thread thread =newThread(runnable);
thread.start();
}
}

用Timer和TimerTask

上面的实现是非常快速简便的,但它也缺少一些功能。
用Timer和TimerTask的话与上述方法相比有如下好处:

  • 当启动和去取消任务时可以控制
  • 第一次执行任务时可以指定你想要的delay时间

在实现时,Timer类可以调度任务,TimerTask则是通过在run()方法里实现具体任务。
Timer实例可以调度多任务,它是线程安全的。
当Timer的构造器被调用时,它创建了一个线程,这个线程可以用来调度任务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
importjava.util.Timer;
importjava.util.TimerTask;
publicclassTask2 {
publicstaticvoidmain(String[] args) {
TimerTask task =newTimerTask() {
@Override
publicvoidrun() {
// task to run goes here
System.out.println("Hello !!!");
}
};
Timer timer =newTimer();
longdelay =0;
longintevalPeriod =1*1000;
// schedules the task to be run in an interval
timer.scheduleAtFixedRate(task, delay,
intevalPeriod);
}// end of main
}

ScheduledExecutorService

ScheduledExecutorService是从Java SE 5的java.util.concurrent里,做为并发工具类被引进的,这是最理想的定时任务实现方式。
相比于上两个方法,它有以下好处:

  • 相比于Timer的单线程,它是通过线程池的方式来执行任务的
  • 可以很灵活的去设定第一次执行任务delay时间
  • 提供了良好的约定,以便设定执行的时间间隔

我们通过ScheduledExecutorService#scheduleAtFixedRate展示这个例子,通过代码里参数的控制,首次执行加了delay时间:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
importjava.util.concurrent.Executors;
importjava.util.concurrent.ScheduledExecutorService;
importjava.util.concurrent.TimeUnit;
publicclassTask3 {
publicstaticvoidmain(String[] args) {
Runnable runnable =newRunnable() {
publicvoidrun() {
// task to run goes here
System.out.println("Hello !!");
}
};
ScheduledExecutorService service = Executors
.newSingleThreadScheduledExecutor();
service.scheduleAtFixedRate(runnable,0,1, TimeUnit.SECONDS);
}
}







分享到:
评论

相关推荐

    Java--Timer--TimerTask--.rar_java timer

    在Java编程语言中,`Timer`和`TimerTask`是两个关键类,它们用于调度周期性的任务执行。这两个类在多线程环境下尤其有用,能够帮助开发者安排在将来某一特定时间或定期执行的任务。让我们深入了解一下`Timer`和`...

    Timer定时器的使用方法

    3. 计划任务:使用 `schedule()` 或 `scheduleAtFixedRate()` 方法来安排 `TimerTask` 的执行。前者按指定延迟后首次执行,然后每次间隔指定的时间执行;后者则保证两次执行之间的间隔固定,即使上一次执行超时也...

    java定时器Timer

    - 使用`Timer`时需要注意内存泄漏问题,因为`TimerTask`实例如果不被正确取消,可能会导致`Timer`线程无法终止,即使所有非守护线程已经结束。 - 可以通过`Timer.cancel()`方法来取消定时器,这将取消所有已安排但未...

    Java中的Timer和TimerTask的使用.doc

    在Java编程语言中,`Timer`和`TimerTask`是两个关键的类,它们用于创建和管理定时任务。`Timer`类提供了一种机制来安排在未来某一特定时间或...正确理解和使用这两个类可以帮助开发者更有效地管理异步任务和系统调度。

    时钟Timer钟表Timer

    2. 非阻塞式Timer:使用回调函数或事件来通知时间到,不会阻塞线程,更适合多线程环境。 3. 定时器轮询:通过周期性检查当前时间与设定时间的差值来判断是否触发事件,适用于精度要求不高的场景。 四、编程语言中的...

    Java定时器

    - **取消任务**:使用`Timer`的`cancel()`方法来取消未执行的任务,这在需要提前终止定时任务时非常有用。 ##### 2. `java.util.TimerTask`类 `TimerTask`是`Timer`类的工作马,它是`Timer`执行的具体任务的载体。...

    java-timer的应用

    这个框架可能包括自定义的Scheduler类,它可以使用日历算法计算任务的下一次执行时间,确保在各种时间调整条件下都能正确触发。通过这种方式,Java应用程序可以更灵活地处理定时任务,从而满足各种实际业务场景的...

    java类Timer和TimerTask的使用.pdf

    Java中的`Timer`和`TimerTask`类是用于创建和管理定时任务的工具,它们提供了在特定时间点或按照预设间隔执行任务的功能。...通过正确使用这两个类,你可以构建出高效且易于维护的定时任务管理方案。

    Java中Timer的用法详解

    虽然`Timer` 类在许多情况下足够使用,但Java 5 引入的`java.util.concurrent` 包提供了更强大且线程安全的定时执行工具,如`ScheduledExecutorService` 和 `ScheduledThreadPoolExecutor`。这些类提供了更多的控制...

    Java课设:内有课程设计报告以及完整代码

    5. **计时器**:Java Timer类和TimerTask类可以创建定时任务,用于执行周期性的操作,如定时检查更新、执行后台清理工作等。 6. **网络编程**:Java的Socket编程接口使得开发者能够创建网络客户端和服务端,实现...

    Java中Timer的schedule()方法参数详解

    Java中Timer的schedule()方法参数详解 Java中Timer的schedule()方法是Java...Java中Timer的schedule()方法是实现定时任务的重要机制,需要正确地理解和使用schedule()方法的参数和执行结果,以便实现正确的定时任务。

    Android---Service Timer之执行周期任务

    Timer和TimerTask是Java提供的定时任务工具,它们也可以在Android环境中使用。Timer创建了一个调度器,而TimerTask则是一个可以被调度的任务对象。通过设置延迟时间和间隔时间,我们可以让Timer定期执行特定的...

    java计时器代码 可以z在Eclipse下直接运行

    在Java中,我们可以使用`java.util.Timer`类和`java.util.TimerTask`类来创建和管理计时器。下面我们将深入探讨这两个类以及如何在Eclipse环境下编写和运行一个简单的计时器程序。 1. `java.util.Timer` 类: - `...

    几种定时任务(Timer、TimerTask、ScheduledFuture)的退出—结合真实案例【JAVA并发】.docx

    本文将结合实际案例探讨如何使用Timer、TimerTask以及ScheduledFuture来实现定时任务,并着重讲解它们的退出机制。 首先,我们来看Timer和TimerTask的使用。Timer类是一个用于调度定时任务的工具,它使用单个后台...

    Java-FootballGame.rar_java 足球_java足球小游戏

    Java 中可以通过 `java.util.Timer` 类或者 `javax.swing.Timer` 来实现定时更新游戏状态。 - **碰撞检测**:足球游戏中的碰撞检测至关重要,包括球员与球员、球员与球之间的碰撞。这通常涉及到几何形状的比较和...

    Android定时器Timer的停止和重启实现代码

    at java.util.Timer.schedule(Timer.java:248) at com.example.zhongzhi.gate_control_scheme.MainActivity.onClick(MainActivity.java:401) at android.view.View.performClick(View.java:5637) at android.view....

    使用Timer和TimerTask实现周期任务

    此外,`TimerTask` 的取消和 `Timer` 的停止也需要注意正确使用,避免资源泄漏。例如,当不再需要执行任务时,应调用 `TimerTask.cancel()` 方法取消任务,并且在程序退出前调用 `Timer.cancel()` 来停止计时器,...

    java使用定时器,定时发送邮件

    在Java编程中,定时任务是常见的一种需求,例如定时发送邮件。这通常涉及到Java的定时器(Timer)类和相关的API。...同时,确保正确引用和使用邮件相关的库文件,如JavaMail,以完成邮件的创建和发送。

    java.util.ConcurrentModificationException 异常问题详解1

    Java.util.ConcurrentModificationException 异常问题详解 ...ConcurrentModificationException 异常是 Java 集合框架中的一个重要概念,了解这个异常可以帮助我们更好地使用 Java 集合框架,避免一些常见的错误。

    java时间控制代码

    ### Java时间控制代码详解 #### 一、概述 在Java编程中,经常需要对程序的执行时间进行精确控制,例如定时任务、...需要注意的是,在使用`Timer`时要确保资源的正确管理,特别是在多线程环境下,以避免潜在的问题。

Global site tag (gtag.js) - Google Analytics