本文主要是介绍java之定时器Timer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 1 概览
- 2 终止Timer线程
- 3 反复执行一个任务
- 4 进一步分析schedule和scheduleAtFixedRate
- 5 一些注意的问题
1 概览
Timer
是一种定时器工具,用来在一个后台线程计划执行指定任务。它可以计划执行一个任务一次或反复多次。
TimerTask
一个抽象类,它的子类代表一个可以被Timer
计划的任务。
简单的一个例程:
import java.util.Timer;
import java.util.TimerTask;
/**
* Simple demo that uses java.util.
* Timer to schedule a task to execute
* once 5 seconds have passed.
*/
public class Reminder { Timer timer; public Reminder(int seconds) { timer = new Timer(); timer.schedule(new RemindTask(), seconds*1000); }
class RemindTask extends TimerTask { public void run() { System.out.println("Time's up!"); timer.cancel(); //Terminate the timer thread } } public static void main(String args[]) { System.out.println("About to schedule task."); new Reminder(5); System.out.println("Task scheduled."); }}
运行结果:
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();timer.schedule(new RemindTask(), time);
2 终止Timer线程
默认情况下,只要一个程序的timer
线程在运行,那么这个程序就会保持运行。当然,可以通过以下四种方法终止一个timer
线程:
- timer.cancle()方法
调用timer
的cancle
方法。可以从程序的任何地方调用此方法,甚至在一个timer task
的run
方法里 - 成为daemon线程
让timer
线程成为一个daemon
线程(可以在创建timer
时使用new Timer(true)
达到这个目地),这样当程序只有daemon
线程的时候,它就会自动终止运行。 - 删除timer对象引用
当timer
相关的所有task
执行完毕以后,删除所有此timer
对象的引用(置成null
),这样timer
线程也会终止 - System.exit方法
调用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;/**
* Simple demo that uses java.util.Timer to schedule a task to execute
* once 5 seconds have passed.
*/public class ReminderBeep {Toolkit toolkit;Timer timer;public ReminderBeep(int seconds) {toolkit = Toolkit.getDefaultToolkit();timer = new Timer();timer.schedule(new RemindTask(), seconds*1000);}class RemindTask extends TimerTask {public void run() {System.out.println("Time's up!");toolkit.beep();//timer.cancel(); //Not necessary because we call System.exitSystem.exit(0); //Stops the AWT thread (and everything else)}}public static void main(String args[]) {System.out.println("About to schedule task.");new ReminderBeep(5);System.out.println("Task scheduled.");}
}
3 反复执行一个任务
先看一个例子:
public class AnnoyingBeep {Toolkit toolkit;Timer timer;public AnnoyingBeep() {toolkit = Toolkit.getDefaultToolkit();timer = new Timer();timer.schedule(new RemindTask(),0, //initial delay1*1000); //subsequent rate}class RemindTask extends TimerTask {int numWarningBeeps = 3;public void run() {if (numWarningBeeps > 0) {toolkit.beep();System.out.println("Beep!");numWarningBeeps--;} else {toolkit.beep();System.out.println("Time's up!");//timer.cancel(); //Not necessary because we call System.exitSystem.exit(0); //Stops the AWT thread (and everything else)}}}...
}执行,你会看到如下输出: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
每隔一秒执行一次。
如下所列为所有Time
r类用来制定计划反复执行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
2
个参数的schedule
在制定任务计划时, 如果指定的计划执行时间scheduledExecutionTime<=systemCurrentTime
,则task
会被立即执行。scheduledExecutionTime
不会因为某一个task
的过度执行而改变。
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
个参数的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
类的线程安全的
这篇关于java之定时器Timer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!