1. 整体图解
2. 包含任务执行逻辑的 TimerTask
抽象类
- 任务抽象类
TimerTask
的生命周期表示如下:
- 任务抽象类
TimerTask
的属性详细解释如下:
- 任务抽象类
TimerTask
的实例方法:
3. 任务队列 TaskQueue
类
TaskQueue
内部采用最小堆来实现优先队列, 其各种操作的复杂度不超过O(logn)
-
TaskQueue
类的属性
-
TaskQueue
类的实例方法
4. 执行任务的线程类 TimerThread
执行任务的线程类
TimerThread
继承Thread
类, 用来执行任务队列中的任务, 因此,Timer
类调度的所有任务都是在单线程中按执行时间先后顺序执行的
-
TimerThread
类的属性
-
TimerThread
类的实例方法
mainloop
方法详细解释如下:
private void mainLoop() {
while (true) {
try {
TimerTask task;
boolean taskFired;
synchronized (queue) {
// 任务队列为空, 让当前执行线程放弃queue锁
while (queue.isEmpty() && newTasksMayBeScheduled) {
queue.wait();
}
// 执行期间发现任务队列为空, 即没有任务需要执行, 因此跳出循环
if (queue.isEmpty()) {
break;
}
long currentTime, executionTime;
task = queue.getMin();
synchronized (task.lock) {
if (task.state == TimerTask.TimerTaskStatus.CANCELLED) {
queue.removeMin();
continue; // 开始下一次循环去执行下一个任务
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if (taskFired = (executionTime <= currentTime)) { // 任务的开始时间早于当前时间, 则立即执行
if (task.period == 0) { // 非周期型任务
queue.removeMin();
task.state = TimerTask.TimerTaskStatus.EXECUTED;
} else { // 周期型任务
// schedule 与 scheduleAtFixedRate 的区别体现在这里
// 当执行时间早于当前时间时, schedule系列方法执行时没有追赶性, scheduleAtFixedRate系列方法执行时具有追赶性
queue.rescheduleMin(task.period < 0 ? currentTime - task.period : executionTime + task.period);
}
}
}
if (!taskFired) { // 还未到时间执行任务
queue.wait(executionTime - currentTime);
}
}
if (taskFired) { // 可以执行任务(注意: 没有锁)
task.run();
}
} catch (InterruptedException e) {
}
}
}
5. Timer
类解析
-
Timer
类的属性
-
Timer
类的构造方法
-
Timer
类的cancel()
方法
-
schedule
系列方法
-
scheduleAtFixedRate
系列方法
schedule
和 scheduleAtFixedRate
方法的具体执行逻辑放在 sched
方法上:
private void sched(TimerTask task, long time, long period) {
// 验证参数是否正确
if (time < 0) {
throw new IllegalArgumentException("Illegal execution time.");
}
if (Math.abs(period) > (Long.MAX_VALUE >> 1)) {
period >>= 1;
}
// 将任务task的属性设置好并存放在任务队列queue上
synchronized (queue) {
if (!thread.newTasksMayBeScheduled) {
throw new IllegalArgumentException("Timer already cancelled.");
}
synchronized (task.lock) {
if (task.state != TimerTask.TimerTaskStatus.VIRGIN) {
throw new IllegalArgumentException("Task already scheduled or cancelled!");
}
task.nextExecutionTime = time;
task.period = period;
task.state = TimerTask.TimerTaskStatus.SCHEDULED;
}
queue.add(task);
// 若加入任务前队列为空则要通知执行任务的线程, 使其从WAITING状态切换为RUNNABLE状态
if (queue.getMin() == task) {
queue.notify();
}
}
}
注意:
schedule
和scheduleAtFixedRate
方法的区别在于当执行时间早于当前时间时,schedule
方法不具有追赶性, 而scheduleAtFixedRate
方法具有追赶性;