Timer中最主要由三个部分组成:
他们之间的关系可以通过下面图示:
在这个图中,可以清楚地看到这Timer本身及其和这三个部分的关系:
1. Timer可以看作是面向开发人员的一个"接口"
2. 所有向Timer添加的任务都会被放入一个TaskQueue类型的任务队列中去.(如何安排任务优先级顺序下文会讲)
3. 任务调度由TimerThread负责.
任务单元 TimerTask
-
- int
state = VIRGIN; -
- static
final int VIRGIN = 0; - static
final int SCHEDULED = 1; - static
final int EXECUTED = 2; - static
final int CANCELLED = 3;
以及一个比较重要的两个成员变量:
nextExecutionTime
这个值是作为任务队列中任务排序的依据.
period
(固定速率:
任务队列 TaskQueue
[添加任务]
- void
add(TimerTask task) { -
if (size + 1 == queue.length) -
queue = Arrays.copyOf(queue, 2 * queue.length); -
queue[++size] = task; -
fixUp(size); - }
- private
void fixUp(int k) { -
while (k > 1) { -
int j = k >> 1; // 对于正数,右移位 <==> j = k/2, 所以j的位置就是k的父亲节点 -
if (queue[j].nextExecutionTime <= queue[k].nextExecutionTime) -
break; -
TimerTask tmp = queue[j]; -
queue[j] = queue[k]; -
queue[k] = tmp; -
k = j; -
} - }
[移除任务]
- void
removeMin() { -
queue[1] = queue[size]; -
queue[size--] = null; // Drop extra reference to prevent memory leak -
fixDown(1); - }
-
- private
void fixDown(int k) { -
int j; -
// 如果还没有到队列的最后,并且没有溢出( j > 0 ) -
// 在没有出现溢出的情况下, j = k << 1 等价于 j = 2 * k ; -
while ((j = k << 1) <= size && j > 0) { -
// 找到k的两个孩子中小的那个. -
if (j < size && queue[j].nextExecutionTime > queue[j + 1].nextExecutionTime) -
j++; // j indexes smallest kid -
// 找到这个较小的孩子后,(此时k是父亲,j是较小的儿子),父亲和儿子互换位置,即k和j换位子.这样一直下去就可以将这个较大的queue[1]向下堆底移动了. -
if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime) -
break; -
TimerTask tmp = queue[j]; -
queue[j] = queue[k]; -
queue[k] = tmp; -
k = j; -
} - }
下面来看看任务调度者是如何工作的.
任务调度 TimerThread
关于任务调度主要要讲下一个成员变量 newTasksMayBeScheduled 和 调度方法 mainLoop().
- private
void mainLoop() { -
while (true) { -
try { -
TimerTask task; -
boolean taskFired = false; -
synchronized (queue) { -
while (queue.isEmpty() && newTasksMayBeScheduled) { -
queue.wait(); -
} -
if (queue.isEmpty()) -
break; // 直接挑出mainLoop了. -
long currentTime, executionTime; -
task = queue.getMin(); // 获取这个任务队列第一个任务 -
synchronized (task.lock) { -
if (task.state == TimerTask.CANCELLED) { -
queue.removeMin(); -
continue; -
} -
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); -
} -
} -
}//释放锁 -
if (!taskFired) -
queue.wait(executionTime - currentTime); -
} -
if (taskFired) // Task fired; run it, holding no locks -
task.run(); -
} catch (InterruptedException e) { -
} -
}// while(true) -
}
newTasksMayBeScheduled变量用来表示是否需要继续等待新任务了.
默认情况这个变量是true
任务调度: mainLoop()方法中的一个while可以理解为一次任务调度:
STEP 1
STEP 2
STEP 3
STEP 4:
STEP 5