一、TimerTask
要使用Timer定时器就不得不来了解一下TimerTask这个类,这个类是用来专门生产Timer的调度任务的。
参数
1. int state; 该字段用来标记任务的当前状态
2. long nextExecutionTime; 该字段记录任务的执行时间;若任务为重复执行任务,则该字段会在下次执行之前更新
3. long period = 0; 该字段记录重复执行任务的执行间隔,为0时表示该任务只执行一次
4. 四个静态常量
(1) VIRGIN = 0; state默认值为0,任务为新建状态时state为该值
(2) SCHEDULED = 1; 当Timer对象将该任务使用schedule或scheduleAtFixedRate添加进待执行任务队列时,state为该值
(3) EXECUTED = 2; 如果该任务为已执行状态或正在执行状态且未被删除则state为该值
(4) CANCELLED = 3; 该任务为删除状态,state为该值(调用cancel()方法)
方法
1. public astract void run() {}
该方法即定时任务需要完成的工作,我们创建一个定时任务时需要重写该方法
2. public boolean cancel() {}
将该任务从就绪状态变更为删除状态,返回值为(state == SCHEDULED),该方法仅对就绪状态的方法有效
3. public long scheduleExecutionTime() {}
返回该任务最近一次的执行时间
二、Timer
Timer是一个定时器,用来执行计划好的TimerTask任务。在Timer中有两个内部类。一个是TimerThread,继承了Thread类,用来创建执行定时任务的线程;另一个是
TaskQueue,内部管理了一个TimerTask[]数组,用来存储待执行的定时任务
1. TimerThread
参数
1. boolean newTasksMayBeScheduled = true;
标记,当该值为false时定时器Timer对象不再可用(不可再向任务队列添加就绪状态任务)
2. TaskQueue queue;
待执行的定时任务队列
方法
1. public void run() {}
线程的启动方法
2. public void mainloop() {}
真正执行定时任务的方法。在这里每次会取小顶堆的顶部元素,即执行时间距离当前时间最近的一个TimerTask准备执行,当
nextExecutionTime<=currentTime时该定时任务便会执行。如果该任务为一次性任务,则该任务会从TaskQueue中移除,若为
重复执行任务,则会计算下一次的执行时间
2. TaskQueue
TaskQueue维护了一个TaskTask数组,使用到了最小堆的算法,最小堆的顶部即执行时间最接近当前时间的定时任务。
参数
1. TimerTask[] queue = new TimerTask[128];
TimerTask数组
2. private int size = 0;
记录当前TaskQueue中定时任务的数量
方法
1. int size() {return size}
返回当前TaskQueue中定时任务的数量
2. void add(TimerTask task) {}
向TaskQueue中添加定时任务
3. getMin() {}
返回最小堆堆顶
4. get(int i) {}
获取指定索引处的TimerTask对象
5. removeMin() {}
移除最小堆堆顶
6. quickRemove(int i) {}
快速移除指定索引处的TimerTask对象
7. rescheduledMin(long newTime) {}
重新设置重复任务的下一次执行时间
8. isEmpty() {}
返回布尔值,TaskQueue是否为空
9. clear() {}
清空任务队列
10. fixUp() {}
上浮
11. fixDown() {}
下沉
12. headify() {}
堆排序
3. Timer
参数
1. TaskQueue queue;
TaskQueue对象
2. TimerThread thread;
执行定时任务的线程
3. private final Object threadReaper;
重写了finalize方法,在Timer对象没有活跃引用以及TaskQueue中没有任务时停止Timer计时器
4. AtomicInteger nextSerialNumber;
用来生成线程ID
构造函数
1. Timer();
默认的构造函数会默认生成一个线程名"Timer-"+serialNumber(),然后调用Timer(String name)构造函数
2. Timer(String name)
传入线程名
3. Timer(boolean isDamon)
传入是否设置为守护线程,生成一个默认线程名"Timer-"+serialNumber(),然后调用Timer(String name, boolean isDamon)
4. Timer(String name, boolean isDamon)
传入线程名和是否守护线程
方法
1. int serialNumber() {return nextSerialNumber.getAndIncrement();}
返回一个序列号
2. public void schedule(TimerTask task, long delay)
传入一个TimerTask对象和一个延迟执行的时延(单位为毫秒),使用该方法添加定时任务默认为只执行一次的任务
3. public void schedule(TimerTask task, Date time)
传入一个TimerTask对象和一个任务执行的Date时间对象,使用该方法添加定时任务默认为只执行一次的任务
4. public void schedule(TimerTask task, long delay, long period)
传入一个TimerTask对象,delay为任务第一次执行距离当前时间的时延,period为重复任务的执行时间间隔
5. public void schedule(TimerTask task, Date time, long period)
传入一个TimerTask对象,time为任务第一次执行的时间,period为重复任务的执行时间间隔
6. public void scheduleAtFixedRate(TimerTask task, long delay, long period)
传入一个TimerTask对象,delay为任务第一次执行距离当前时间的时延,period为重复任务的执行时间间隔
7. public void scheduleAtFixedRate(TimerTask task, Date time, long period)
传入一个TimerTask对象,time为任务第一次执行的时间,period为重复任务的执行时间间隔
8. public void sched(TimerTask task, long time, long period)
以上添加定时任务的方法最终都是调用该方法进行定时任务的添加。第一个参数为TimerTask对象,第二个参数是
定时任务的第一次执行时间,第三个参数为0时表示该任务执行一次(不是重复任务)
9. public void cancel()
停止计时器和清空TaskQueue任务列表
10. public int purge()
清空TaskQueue中状态为CANCELLED的任务,并返回删除的数量
可能会有人疑惑schedule和scheduleAtFixedRate的区别。事实上两者的区别在于调用sched添加定时任务时,schedule的period参数为负数,scheduleAtFixedRate传入
的period参数为正数。那这异味着什么呢?其实这个区别是在确定重复任务的下一次执行时间时体现出来,在TimerThread的mainloop方法中有这么一行代码
queue.rescheduleMin(task.period<0 ? currentTime - task.period : executionTime + task.period);
即以schedule方式添加的重复任务的下一次执行时间是以前一次执行的完成时间为基准计算的,而scheduleAtFixedRate方式添加的重复任务的下一次执行时间是以前一次计划
执行时间为基准计算的
出处:https://www.cnblogs.com/huangzhx0420/p/huangzhx0420_Timer.html