Timer和TimerTask
源码:Timer持有TaskQueue对象,TaskQueue通过数组持有TimerTask对象private TimerTask[] queue = new TimerTask[128];
。128只是初始数组大小,如果超过128个,会新建一个更大的数组去持有TimerTask对象。
TimerTask代表一个需要[多次]执行的任务,它实现了Runnable接口,可以在run()方法中定义任务逻辑。而Timer负责制定调度规则并调度TimerTask。
TimerTask
每当执行任务时,上次任务和本次任务使用相同的TimerTask实例。所以,如果TimerTask对象中拥有状态,那么这些状态对于后面的执行是可见的。
TimerTask是一个抽象类,只有以下3个方法:
-
abstract void run()
:子类覆盖这个方法并定义任务执行逻辑,每次执行任务时,run()
方法就被调用一次。 -
boolean cancel()
:取消任务。调用该方法后,后续的执行安排将取消。注:正在执行的任务不受影响。 -
long scheduledExecutionTime()
:返回此任务的计划执行时间点。如果在任务执行过程中调用此方法,则返回此次执行所对应的计划执行时间(一个任务的实际执行时间和计划执行时间可能不一致)。该方法一般在run()
方法内调用,用户可以通过该方法判断本次执行的时间点是否过晚,并据此决定是否要取消本次执行。该方法一般在固定频率执行时使用才会有意义。
Timer
Timer只能以这样的方式对任务进行调度:在延迟一段时间或在指定时间点后运行一次任务或周期性地运行任务。实际上,在Timer内部使用Object#wait(long time)
进行任务的时间调度。这种机制不能保证任务的实时执行,只是一个粗略的近似值。
每个Timer对象都有一个对应的“背景线程”,它负责调度并执行Timer中所有的TimerTask。由于所有的TimerTask都在这个线程中执行,所以TimerTask的执行时间应该比较短。如果一个TimerTask的执行占用过多的时间,那么后面的任务就会受到影响。由于后续任务在调度时间轴上受到了“挤压”,所以可能会造成“扎堆”执行的情况。
当Timer中所有的TimerTask已经执行完成并且Timer对象没有外部引用时,Timer的任务执行线程才会结束,但这可能需要很长的时间。因此,Timer在默认情况下使用非守护线程(daemon Thread),这样用户就可以在应用程序中通过Timer#cancel()
方法手工结束Timer。如果希望尽快结束Timer中的任务,则可以调用TimerTask#cancel()方法来达到目的。
Timer的构造函数在创建Timer对象的同时将启动一个Timer背景线程。
构造函数
Timer()
:创建一个Timer,背景线程是非守护线程。Timer(boolean isDaemon)
:JDK1.5;true:守护线程;false:非守护线程。Timer(String name)
:通过name为关联背景线程指定名称。Timer(String name,boolean isDaemon)
:JDK1.5
执行一次任务
schedule(TimerTask task,Date time)
:在特定时间点执行一次任务。schedule(TimerTask task,long delay)
:延迟指定时间后执行一次任务,delay的单位为毫秒。
固定间隔执行任务
通过以下方法按固定间隔执行任务,间隔时长为上次任务执行完成的时间点到下次任务开始执行的时间点,任务的执行可能产生时间的漂移。
schedule(TimerTask task,Date firstTime,long period)
:从指定时间点开始周期性地执行任务,period的单位:毫秒,后一次执行将在前一次执行完成后才开始计时。如任务被安排每2秒执行一次,假设第一次任务在0秒时间点开始执行并花费了1.5秒,则第二次将在第3.5秒时执行。schedule(TimerTask task,long delay,long period)
:在延迟指定时间后,周期性地执行任务。
固定频率执行任务
scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
:在指定时间点后,以指定频率执行任务。假设一个任务被安排每2秒执行一次,如果第一次执行话费了1.5秒,则在0.5秒后,第二次任务又会开始执行,以保证固定的执行频率。如果一次任务执行时间过长,后续任务在调度时间轴上受到了“挤压”,所以可能会造成“扎堆”执行的情况。scheduleAtFixedRate(TimerTask task,long delay,long period)
:在延迟一段时间后,以指定频率执行任务。
控制方法
cancel()
:取消Timer的执行,并丢弃所有被调度的TimerTask,不过正在执行的任务不受影响。Timer被取消后,不能调度新的TimerTask。purge()
:将所有已经取消的TimerTask从Timer队列中清除。如果TimerTask没有外部引用,就可以被垃圾回收。一般情况下无须调用该方法,只有在某些特殊情况下,当一次性取消多个TimerTasks后,调用该方法才有意义。