单线程模式(由 Timer和TimerTask 协同实现)
使用util包下面的Timer工具,简单看一下Timer类的组成。
queue: TaskQueque,本质是一个 TimerTask数组,初始化大小为 128
thread:TImerThread ,本质就是一个线程,Timer单线程定时任务的执行线程
.... , 其他以后再看
其中,Timer中有六个方法
两个参数的方法,一个是设置任务开始延迟时间,一个是设置任务开始的时间。都是一次性任务。
有三个参数的方法比两个参数的方法多个long类型的间隔时间参数。其中能定时执行的原理是 , mianLoop()里面是个死循环
下面讲一下这两个方法的差别
再仔细分析 , 下面这段代码的流程,在详细分析一下
TimerTask task;
boolean taskFired; synchronized(queue) { // Wait for queue to become non-empty while (queue.isEmpty() && newTasksMayBeScheduled) queue.wait(); if (queue.isEmpty()) break; // Queue is empty and will forever remain; die // Queue nonempty; look at first evt and do the right thing long currentTime, executionTime; task = queue.getMin(); synchronized(task.lock) {
// 当前任务为取消状态,就从queque中去除当前任务 if (task.state == TimerTask.CANCELLED) {
// 去除第一个元素 queue.removeMin(); continue; // No action required, poll queue again } currentTime = System.currentTimeMillis(); executionTime = task.nextExecutionTime;
//当 当前时间>=应该执行的时间, 任务就激活 if (taskFired = (executionTime<=currentTime)) {
// 如果period == 0说明是一次性任务,从queque去除(执行在下面,不要担心不会执行,这里先去除) if (task.period == 0) { // Non-repeating, remove queue.removeMin(); task.state = TimerTask.EXECUTED; } else { // Repeating task, reschedule
// 重新设置task的nextExecutionTime,schedule传进来的是负数, schuduleAtFixedRate是正数 , 设置完后还会根据 nextExecutionTime进行排序 queue.rescheduleMin( task.period<0 ? currentTime - task.period : executionTime + task.period); } } } if (!taskFired) // Task hasn't yet fired; wait queue.wait(executionTime - currentTime); } if (taskFired) // Task fired; run it, holding no locks
//执行任务
task.run();
其中 rescheduleMin 中的排序逻辑如下
由此可见,会在queue里面选出一个下次执行时间最小的task放到队首
执行结果借鉴如下
其中 task1是schedule执行的 , nextExecutionTime = currentTime + period
其中 task是scheduleAtFixedRate执行的 , nextExecutionTime = executionTime(上一个) + period
可见,除了新添加task放到队首外,其余每次都是选最早的那个任务开始执行