Timer 定时器执行过程:Timer TimerTask TimerQueue
Timer是一个单线程 + 最小堆 + 不断轮询
Timer time=newTimer();
n 调用构造方法创建timer类
public Timer(){
this("Timer-"+ serialNumber());
}
private final static AtomicIntegernextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
return nextSerialNumber.getAndIncrement();
}
This方法: 这个name是Timer-0
public Timer(String name) {
thread.setName(name);
thread.start();
}
对name设置值
public final void setName(String name) {
checkAccess();
this.name = name.toCharArray();
}
checkAccess();
这个是权限控制
publicfinalvoid checkAccess() {
SecurityManager security =System.getSecurityManager();
if (security != null) {
security.checkAccess(this);
}
}
SecurityManager 对运行的java代码进行权限控制,防止恶意代码的运行
开启线程:
thread.start(); 这个运行的是timerThread 的run方法
这里先略过,
time.schedule(new TaskTest(), 1000); 定时类设置任务和每次时间间隔执行的时间
public void schedule(TimerTask task, long delay){
if (delay < 0)
throw new IllegalArgumentException("Negativedelay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
//初始化task、 task 执行任务 time时间period 间隔
privatevoid sched(TimerTask task, long time, long period) {
if (time < 0)
thrownew IllegalArgumentException("Illegal executiontime.");
// Constrain value of periodsufficiently to prevent numeric
// overflow while still beingeffectively infinitely large.
if (Math.abs(period) >(Long.MAX_VALUE >> 1)) 间隔的绝对值 大于 LONG的最大值右移动一位 Long.MAX_VALUE =9223372036854775807
Long.MAX_VALUE >> 1 =4611686018427387903
period >>= 1; period右移一位并重新赋值给自己
这里插一下开始的时候创建了thread TimerThread thread = new TimerThread(queue);
Queue private TimerTask[] queue = newTimerTask[128];
synchronized(queue) {
if (!thread.newTasksMayBeScheduled) 判断 线程的newTasksMayBeScheduled 这个值是true还是false
thrownew IllegalStateException("Timer alreadycancelled.");如果是true 就报错
synchronized(task.lock) {
if (task.state != TimerTask.VIRGIN) 判断线程状态 task。State 初始是0 TimerTask.VIRGIN 初始也是0,如果初始状态不等就报错
thrownew IllegalStateException("Task already scheduledor cancelled");
task.nextExecutionTime = time; 任务的下一个执行时间是time
task.period = period; 间隔是period
task.state = TimerTask.SCHEDULED; TimerTask.SCHEDULED =1
}
queue.add(task); 把任务加入到队列
这里插入一下queue的方法add
void add(TimerTask task) {
// Grow backing store if necessary
if (size + 1 == queue.length) size 初始化是0 ,如果size+1是现在队列的长度就默认扩容2倍
queue = Arrays.copyOf(queue, 2*queue.length);
queue[++size] = task; 加入队列 queue是TimerTask数组,默认初始化128内存
fixUp(size);
这里插入fixup 比较队列中现在这个任务和上一个任务的执行时间
privatevoidfixUp(int k) {
while (k> 1) {
int j =k >> 1; 右移动是减少 2>>1 变成1
if (queue[j].nextExecutionTime<= queue[k].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] =tmp;
k = j; 这里把k减少
}
}
}
if (queue.getMin() == task) 如果队列中的 和现在这个task一样 就唤醒其他等待线程
getMIn=queue【1】;
queue.notify();
}
}
、task的执行:
publicvoidrun() {
try {
mainLoop();
} finally {
// Someonekilled this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsoletereferences
}
}
}
privatevoidmainLoop() {
while (true) { //轮循环
try {
TimerTask task;
booleantaskFired;
synchronized(queue) {
// Wait forqueue to become non-empty
while (queue.isEmpty()&& newTasksMayBeScheduled) 如果队列是空的就进入等待
queue.wait();
if (queue.isEmpty())
break; //Queue is empty and will forever remain; die
// Queuenonempty; look at first evt and do the right thing
longcurrentTime, executionTime;
task = queue.getMin();
synchronized(task.lock) {
if(task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, pollqueue again
}
currentTime = System.currentTimeMillis();
executionTime = task.nextExecutionTime;
if(taskFired = (executionTime<=currentTime)) { //比较执行时间和系统时间
if(task.period == 0) { //Non-repeating, remove
queue.removeMin();
task.state =TimerTask.EXECUTED;
} else { //Repeating task, reschedule
queue.rescheduleMin(
task.period<0? currentTime - task.period
: executionTime + task.period); //这里计算下一次的执行时间,轮询的时候比较下一次的执行时间,如果时间不对就不执行 这里有个问题,就是为什么动态循环都是只有下下一次才能改变这个时间间隔,而不是下一次,因为这次就决定了下次时间的决定。所以timer没办法改变下一次的执行时间,但是可以改变下下次的执行,那么这里我是不是可以重写这个函数,把执行时间可以从外部传进去。
}
}
}
if(!taskFired) // Task hasn't yet fired; wait
queue.wait(executionTime- currentTime);
}
if(taskFired) // Task fired;run it, holding no locks
task.run();
} catch(InterruptedExceptione) {
}
}
}