目录
前置知识: ①小顶堆定义、删除、插入等.
②线程的基本知识.
一、easy-demo
四个主要的类:
①Timer
②TimerThread
③TaskQueue
④TimerTask
public class TimerDemo {
public static void main(String[] args) {
TimerTask timerTask = new TimerTask() {
@Override
public void run() {
System.out.println("ThreadName = " + Thread.currentThread().getName() + " Time = " + System.currentTimeMillis());
System.out.println("定时任务~");
}
};
Timer timer = new Timer();
long delay = 0;
long period = 1000;
//para1:任务逻辑
//para2:延迟多长时间开始
//para3:执行周期
timer.scheduleAtFixedRate(timerTask,0,period);
}
}
输出结果:每秒执行一次。
ThreadName = Timer-0 Time = 1652606338299
定时任务~
ThreadName = Timer-0 Time = 1652606339309
定时任务~
ThreadName = Timer-0 Time = 1652606340307
定时任务~
ThreadName = Timer-0 Time = 1652606341312
定时任务~
二、关键类的介绍
1.TimerTask类
TimerTask类的主要属性和方法。
作用:用户自定义的定时任务逻辑就写在该实例对象中的run方法中。
public abstract class TimerTask implements Runnable {
//锁对象
final Object lock = new Object();
//task的4个状态,初始为VIRGIN.
//①VIRGIN: This task has not yet been scheduled.
//②SCHEDULED: This task is scheduled for execution
//③EXECUTED: This non-repeating task has already executed
//④CANCELLED: This task has been cancelled
int state = VIRGIN;
//初始状态
static final int VIRGIN = 0;
//已预定状态
static final int SCHEDULED = 1;
//已执行状态
static final int EXECUTED = 2;
//被取消
static final int CANCELLED = 3;
//下一次执行时间(repeat-task)
long nextExecutionTime;
//Period in milliseconds for repeating tasks.
//执行周期 0表示一次性任务 正负值表示周期性任务
long period = 0;
protected TimerTask() {
}
//TimerTask类实现Runnable,创建该实例类必须重写run()
public abstract void run();
//将已预定的task取消,状态变为CANCELLED
public boolean cancel() {
synchronized (lock) {
boolean result = (state == SCHEDULED);
state = CANCELLED;
return result;
}
}
//设置(重复任务的下一次)执行时间
public long scheduledExecutionTime() {
synchronized (lock) {
return (period < 0 ? nextExecutionTime + period
: nextExecutionTime - period);
}
}
}
2.TaskQueue类
任务队列,存放的逻辑结构为小顶堆.
class TaskQueue {
//The TimerTask with the lowest nextExecutionTime is in queue[1]
//一个任务队列,初始为2^7的数组.
//★ 逻辑结构是一个小顶堆,节点权重可视为executeTime 和 currentTime的差值,即最顶部为最先开始执行的task
private TimerTask[] queue = new TimerTask[128];
//队列中 number of task
private int size = 0;
//Returns the number of tasks currently on the queue.
int size() {
return size;
}
//Adds a new task to the priority queue.
//添加一个新的task到队列中,添加到数组末尾,然后进行小顶堆排序
void add(TimerTask task) {
//满了就double扩容
if (size + 1 == queue.length)
queue = Arrays.copyOf(queue, 2*queue.length);
queue[++size] = task;
//★ 小顶堆的插入并排序 细节见下fixUp()方法
fixUp(size);
}
//Return the "head task" of the priority queue.
//获取最先即将执行的方法
TimerTask getMin() {
return queue[1];
}
//移除最先即将执行的方法
//注意:task存在queue[1] ~ queue[n]中,queue[0]不存放.
void removeMin() {
//将最后一个task覆盖第一个,然后将最后一个坑置为null. 符合小顶堆删除的规则.
queue[1] = queue[size];
queue[size--] = null;
//★ 进行小顶堆的排序 详细算法见fixDown()方法
fixDown(1);
}
//Removes the ith element from queue without regard for maintaining the heap invariant
//删除指定位置的task,且不做小顶堆排序.
void quickRemove(int i) {
assert i <= size;
//末尾填坑
queue[i] = queue[size];
queue[size--] = null;
}
//重新设置队头元素的nextExecutionTime,并且做一次小顶堆排序
void rescheduleMin(long newTime) {
queue[1].nextExecutionTime = newTime;
fixDown(1);
}
//判断queue是否为空
boolean isEmpty() {
return size==0;
}
// Removes all elements from the priority queue.
void clear() {
for (int i=1; i<=size; i++)
queue[i] = null;
size = 0;
}
//小顶堆的排序,每个节点只在该父路径上做排序.
private void fixUp(int k) {
//时间复杂度: log2(k)
while (k > 1) {
//j为父节点索引
int j = k >> 1;
if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
k = j;
}
}
//小顶堆的向下排序
private void fixDown(int k) {
int j;
//j为左孩子索引
while ((j = k << 1) <= size && j > 0) {
if (j < size &&
queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
//j为小权重的孩子节点
j++;
if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
k = j;
}
}
//小顶堆的排序,从最后一个有孩子节点的节点开始.
void heapify() {
for (int i = size/2; i >= 1; i--)
fixDown(i);
}
}
3.TimerThread类
关键方法是mainLoop
class TimerThread extends Thread {
//还会有新的task将会被Scheduled
boolean newTasksMayBeScheduled = true;
//任务队列
private TaskQueue queue;
//构造
TimerThread(TaskQueue queue) {
this.queue = queue;
}
public void run() {
try {
mainLoop();
} finally {
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear();
}
}
}
//执行任务队列的主要方法
private void mainLoop() {
while (true) {
try {
TimerTask task;
//taskFired为true表示还未达到执行时间,为false表示已经达到可执行时间.
boolean taskFired;
synchronized(queue) {
//队列为空就等待,等待notify()
while (queue.isEmpty() && newTasksMayBeScheduled)
queue.wait();
if (queue.isEmpty())
break;
long currentTime, executionTime;
//获取最先执行的task
task = queue.getMin();
synchronized(task.lock) {
//如果状态为CANCELLED就从队列移除
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue;
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
//taskFired为true表示还未达到执行时间,为false表示已经达到可执行时间.
if (taskFired = (executionTime<=currentTime)) {
//非重复task
if (task.period == 0) {
//移出队列
queue.removeMin();
//task标志为已执行(实际还未执行)
task.state = TimerTask.EXECUTED;
} else {
//repeat-task
//设置执行周期
//schedule()方法和scheduleAtFixedRate()方法period正负值不同.
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
//等待到执行时间,期间可被唤醒,不被唤醒到时自动醒来.
if (!taskFired)
queue.wait(executionTime - currentTime);
}
//到时执行.run方法即用户自定义的定时任务逻辑.
if (taskFired)
task.run();
} catch(InterruptedException e) {
}
}
}
}
4.Timer类
san在构造方法中可知,new Timer()时,任务线程就已经被start了。
public class Timer {
//★ 任务队列
private final TaskQueue queue = new TaskQueue();
//★ 任务线程
private final TimerThread thread = new TimerThread(queue);
//构造
public Timer(String name) {
thread.setName(name);
//new Timer()时,任务线程就启动了.如果任务队列为空,会卡在mainloop里面wait.
thread.start();
}
//schedule方法
public void schedule(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, -period);
}
//scheduleAtFixedRate方法
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, System.currentTimeMillis()+delay, period);
}
//任务调度核心方法
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;
synchronized(queue) {
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN)
throw new IllegalStateException(
"Task already scheduled or cancelled");
//任务下一次执行时间以及执行周期
task.nextExecutionTime = time;
task.period = period;
//任务标记为已预定
task.state = TimerTask.SCHEDULED;
}
//添加到任务队列中,扔到队尾,然后进行自小而上的小顶堆排序.
queue.add(task);
//如果该任务是最先即将执行的任务,就唤醒TimerThread#mainLoop中的queue.wait().
if (queue.getMin() == task)
queue.notify();
}
}
//清空任务队列,与TimerTask中的cancel做区分.
public void cancel() {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify();
}
}
//将任务队列做一次清除,将所有的CANCELLED的task移除,最后做一次小顶堆排序.返回值为移除CANCELLED状态task的数量.
public int purge() {
int result = 0;
synchronized(queue) {
for (int i = queue.size(); i > 0; i--) {
if (queue.get(i).state == TimerTask.CANCELLED) {
//移除CANCELLED状态的task.
queue.quickRemove(i);
result++;
}
}
//有移除就有可能破坏小顶堆规则,需要重排序.
if (result != 0)
queue.heapify();
}
return result;
}
}
三、demo的执行流程
多熟悉一下这4个类,再写俩demo进行debug一下就熟悉了。