相关类:
Timer : 创建定时任务调度的主类
TimerThread:Timer的一个内部类,继承Thread,负责线程任务的调度
TaskQueue : TImer的一个内部类,调度的任务的队列
TimerTask : 实现Runnable接口的抽象类,负责具体任务的执行逻辑
TimerTask:
/*
* Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util;
/**
* A task that can be scheduled for one-time or repeated execution by a Timer.
*
* @author Josh Bloch
* @see Timer
* @since 1.3
*/
//实现Runnable接口的抽象类,负责具体任务的执行逻辑,一般我们会new一个 TimerTask或者创建一个任务类继承TimerTask,然后实现run方法。
public abstract class TimerTask implements Runnable {
/**
* This object is used to control access to the TimerTask internals.
*/
//内部锁对象,用于控制内部的一个访问
final Object lock = new Object();
/**
* The state of this task, chosen from the constants below.
*/
//任务的状态,初始创建时为这个VIRGIN,原始的
int state = VIRGIN;
/**
* This task has not yet been scheduled.
*/
//刚创建,还没被调度
static final int VIRGIN = 0;
/**
* This task is scheduled for execution. If it is a non-repeating task,
* it has not yet been executed.
*/
//已经被调度
static final int SCHEDULED = 1;
/**
* This non-repeating task has already executed (or is currently
* executing) and has not been cancelled.
*/
//已经内执行,并且没有被取消
static final int EXECUTED = 2;
/**
* This task has been cancelled (with a call to TimerTask.cancel).
*/
//任务被取消
static final int CANCELLED = 3;
/**
* Next execution time for this task in the format returned by
* System.currentTimeMillis, assuming this task is scheduled for execution.
* For repeating tasks, this field is updated prior to each task execution.
*/
//下一次执行时间,任务初始被调度的时候,该值被赋值为第一次执行任务的时间,在任务被调度执行时也会被修改
long nextExecutionTime;
/**
* Period in milliseconds for repeating tasks. A positive value indicates
* fixed-rate execution. A negative value indicates fixed-delay execution.
* A value of 0 indicates a non-repeating task.
*/
//任务处理间隔时间,正数表示该任务是带时间修正的任务,负数表示不带修正的。
long period = 0;
/**
* Creates a new timer task.
*/
//构造方法
protected TimerTask() {
}
/**
* The action to be performed by this timer task.
*/
//具体的任务执行。
public abstract void run();
/**
* Cancels this timer task. If the task has been scheduled for one-time
* execution and has not yet run, or has not yet been scheduled, it will
* never run. If the task has been scheduled for repeated execution, it
* will never run again. (If the task is running when this call occurs,
* the task will run to completion, but will never run again.)
*
* <p>Note that calling this method from within the <tt>run</tt> method of
* a repeating timer task absolutely guarantees that the timer task will
* not run again.
*
* <p>This method may be called repeatedly; the second and subsequent
* calls have no effect.
*
* @return true if this task is scheduled for one-time execution and has
* not yet run, or this task is scheduled for repeated execution.
* Returns false if the task was scheduled for one-time execution
* and has already run, or if the task was never scheduled, or if
* the task was already cancelled. (Loosely speaking, this method
* returns <tt>true</tt> if it prevents one or more scheduled
* executions from taking place.)
*/
//取消任务,
public boolean cancel() {
//加锁,防并发
synchronized(lock) {
//如果线程 已经被调度,返回ture,说明进行了取消操作,如果任务处于其他状态,就返回false了,
boolean result = (state == SCHEDULED);
//标记为取消状态
state = CANCELLED;
return result;
}
}
/**
* Returns the <i>scheduled</i> execution time of the most recent
* <i>actual</i> execution of this task. (If this method is invoked
* while task execution is in progress, the return value is the scheduled
* execution time of the ongoing task execution.)
*
* <p>This method is typically invoked from within a task's run method, to
* determine whether the current execution of the task is sufficiently
* timely to warrant performing the scheduled activity:
* <pre>{@code
* public void run() {
* if (System.currentTimeMillis() - scheduledExecutionTime() >=
* MAX_TARDINESS)
* return; // Too late; skip this execution.
* // Perform the task
* }
* }</pre>
* This method is typically <i>not</i> used in conjunction with
* <i>fixed-delay execution</i> repeating tasks, as their scheduled
* execution times are allowed to drift over time, and so are not terribly
* significant.
*
* @return the time at which the most recent execution of this task was
* scheduled to occur, in the format returned by Date.getTime().
* The return value is undefined if the task has yet to commence
* its first execution.
* @see Date#getTime()
*/
//返回最后一次执行任务的时间
public long scheduledExecutionTime() {
//同步加锁
synchronized(lock) {
//其实就相当于nextExecutionTime - Math.abs(period),用下一次执行的时间减去任务执行间隔,period前面说过了,正负就是为了来标记这个任务是fixed带修正的还是持续延时的,在定时任务触发的时候有相应的处理。
return (period < 0 ? nextExecutionTime + period
: nextExecutionTime - period);
}
}
}
Timer、TaskQueue、TimerThread:
/*
* Copyright (c) 1999, 2008, Oracle and/or its affiliates. All rights reserved.
* ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package java.util;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
/**
* A facility for threads to schedule tasks for future execution in a
* background thread. Tasks may be scheduled for one-time execution, or for
* repeated execution at regular intervals.
*
* <p>Corresponding to each <tt>Timer</tt> object is a single background
* thread that is used to execute all of the timer's tasks, sequentially.
* Timer tasks should complete quickly. If a timer task takes excessive time
* to complete, it "hogs" the timer's task execution thread. This can, in
* turn, delay the execution of subsequent tasks, which may "bunch up" and
* execute in rapid succession when (and if) the offending task finally
* completes.
*
* <p>After the last live reference to a <tt>Timer</tt> object goes away
* <i>and</i> all outstanding tasks have completed execution, the timer's task
* execution thread terminates gracefully (and becomes subject to garbage
* collection). However, this can take arbitrarily long to occur. By
* default, the task execution thread does not run as a <i>daemon thread</i>,
* so it is capable of keeping an application from terminating. If a caller
* wants to terminate a timer's task execution thread rapidly, the caller
* should invoke the timer's <tt>cancel</tt> method.
*
* <p>If the timer's task execution thread terminates unexpectedly, for
* example, because its <tt>stop</tt> method is invoked, any further
* attempt to schedule a task on the timer will result in an
* <tt>IllegalStateException</tt>, as if the timer's <tt>cancel</tt>
* method had been invoked.
*
* <p>This class is thread-safe: multiple threads can share a single
* <tt>Timer</tt> object without the need for external synchronization.
*
* <p>This class does <i>not</i> offer real-time guarantees: it schedules
* tasks using the <tt>Object.wait(long)</tt> method.
*
* <p>Java 5.0 introduced the {@code java.util.concurrent} package and
* one of the concurrency utilities therein is the {@link
* java.util.concurrent.ScheduledThreadPoolExecutor
* ScheduledThreadPoolExecutor} which is a thread pool for repeatedly
* executing tasks at a given rate or delay. It is effectively a more
* versatile replacement for the {@code Timer}/{@code TimerTask}
* combination, as it allows multiple service threads, accepts various
* time units, and doesn't require subclassing {@code TimerTask} (just
* implement {@code Runnable}). Configuring {@code
* ScheduledThreadPoolExecutor} with one thread makes it equivalent to
* {@code Timer}.
*
* <p>Implementation note: This class scales to large numbers of concurrently
* scheduled tasks (thousands should present no problem). Internally,
* it uses a binary heap to represent its task queue, so the cost to schedule
* a task is O(log n), where n is the number of concurrently scheduled tasks.
*
* <p>Implementation note: All constructors start a timer thread.
*
* @author Josh Bloch
* @see TimerTask
* @see Object#wait(long)
* @since 1.3
*/
public class Timer {
/**
* The timer task queue. This data structure is shared with the timer
* thread. The timer produces tasks, via its various schedule calls,
* and the timer thread consumes, executing timer tasks as appropriate,
* and removing them from the queue when they're obsolete.
*/
//定时任务队列,一个timer实例可以调度多个timertask
private final TaskQueue queue = new TaskQueue();
/**
* The timer thread.
*/
//定时器线程,只有1个,可见同时只能调度执行一个任务,具体还要看thread的执行体是怎么做的。
private final TimerThread thread = new TimerThread(queue);
/**
* This object causes the timer's task execution thread to exit
* gracefully when there are no live references to the Timer object and no
* tasks in the timer queue. It is used in preference to a finalizer on
* Timer as such a finalizer would be susceptible to a subclass's
* finalizer forgetting to call it.
*/
//这里这个对象可以理解为线程收割者,目的就是在Timer回收之前,优先执行这个引用复写的finalize方法。方法的内容是修改timer线程的是否可以调度新任务为false,同时唤醒timer线程
private final Object threadReaper = new Object() {
protected void finalize() throws Throwable {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.notify(); // In case queue is empty.
}
}
};
/**
* This ID is used to generate thread names.
*/
//原子操作的一个Integer,静态的,计算timer线程的名字用,平时我们没有定义名称的时候,可以在线程栈里面看到Timer-1、Timer-2的名字,就是这个
private final static AtomicInteger nextSerialNumber = new AtomicInteger(0);
private static int serialNumber() {
return nextSerialNumber.getAndIncrement();
}
/**
* Creates a new timer. The associated thread does <i>not</i>
* {@linkplain Thread#setDaemon run as a daemon}.
*/
//默认的构造方法
public Timer() {
this("Timer-" + serialNumber());
}
/**
* Creates a new timer whose associated thread may be specified to
* {@linkplain Thread#setDaemon run as a daemon}.
* A daemon thread is called for if the timer will be used to
* schedule repeating "maintenance activities", which must be
* performed as long as the application is running, but should not
* prolong the lifetime of the application.
*
* @param isDaemon true if the associated thread should run as a daemon.
*/
//设定是否是守护线程
public Timer(boolean isDaemon) {
this("Timer-" + serialNumber(), isDaemon);
}
/**
* Creates a new timer whose associated thread has the specified name.
* The associated thread does <i>not</i>
* {@linkplain Thread#setDaemon run as a daemon}.
*
* @param name the name of the associated thread
* @throws NullPointerException if {@code name} is null
* @since 1.5
*/
//设定timer线程的名字,以及启动这个线程,这个timer现场就开始运行。
public Timer(String name) {
thread.setName(name);
thread.start();
}
/**
* Creates a new timer whose associated thread has the specified name,
* and may be specified to
* {@linkplain Thread#setDaemon run as a daemon}.
*
* @param name the name of the associated thread
* @param isDaemon true if the associated thread should run as a daemon
* @throws NullPointerException if {@code name} is null
* @since 1.5
*/
//指定名称和是否是守护线程的构造方法
public Timer(String name, boolean isDaemon) {
thread.setName(name);
thread.setDaemon(isDaemon);
thread.start();
}
/**
* Schedules the specified task for execution after the specified delay.
*
* @param task task to be scheduled.
* @param delay delay in milliseconds before task is to be executed.
* @throws IllegalArgumentException if <tt>delay</tt> is negative, or
* <tt>delay + System.currentTimeMillis()</tt> is negative.
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} is null
*/
//我们常见的调度task的api方法之一,指定调度的TimerTask,以及延迟多少毫秒执行,延时时间不能小于0,只执行一次。
public void schedule(TimerTask task, long delay) {
if (delay < 0)
throw new IllegalArgumentException("Negative delay.");
sched(task, System.currentTimeMillis()+delay, 0);
}
/**
* Schedules the specified task for execution at the specified time. If
* the time is in the past, the task is scheduled for immediate execution.
*
* @param task task to be scheduled.
* @param time time at which task is to be executed.
* @throws IllegalArgumentException if <tt>time.getTime()</tt> is negative.
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} or {@code time} is null
*/
//我们常见的调度task的api方法之一,指定调度的TimerTask,以及执行的时刻,只执行一次。
public void schedule(TimerTask task, Date time) {
sched(task, time.getTime(), 0);
}
/**
* Schedules the specified task for repeated <i>fixed-delay execution</i>,
* beginning after the specified delay. Subsequent executions take place
* at approximately regular intervals separated by the specified period.
*
* <p>In fixed-delay execution, each execution is scheduled relative to
* the actual execution time of the previous execution. If an execution
* is delayed for any reason (such as garbage collection or other
* background activity), subsequent executions will be delayed as well.
* In the long run, the frequency of execution will generally be slightly
* lower than the reciprocal of the specified period (assuming the system
* clock underlying <tt>Object.wait(long)</tt> is accurate).
*
* <p>Fixed-delay execution is appropriate for recurring activities
* that require "smoothness." In other words, it is appropriate for
* activities where it is more important to keep the frequency accurate
* in the short run than in the long run. This includes most animation
* tasks, such as blinking a cursor at regular intervals. It also includes
* tasks wherein regular activity is performed in response to human
* input, such as automatically repeating a character as long as a key
* is held down.
*
* @param task task to be scheduled.
* @param delay delay in milliseconds before task is to be executed.
* @param period time in milliseconds between successive task executions.
* @throws IllegalArgumentException if {@code delay < 0}, or
* {@code delay + System.currentTimeMillis() < 0}, or
* {@code period <= 0}
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} is null
*/
//我们常见的调度task的api方法之一,指定调度的TimerTask,延迟多少毫秒执行,重复执行的时间间隔多少毫秒,
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.");
//可以看到,没有fixed的period会被转化为负数,以区分一下。
sched(task, System.currentTimeMillis()+delay, -period);
}
/**
* Schedules the specified task for repeated <i>fixed-delay execution</i>,
* beginning at the specified time. Subsequent executions take place at
* approximately regular intervals, separated by the specified period.
*
* <p>In fixed-delay execution, each execution is scheduled relative to
* the actual execution time of the previous execution. If an execution
* is delayed for any reason (such as garbage collection or other
* background activity), subsequent executions will be delayed as well.
* In the long run, the frequency of execution will generally be slightly
* lower than the reciprocal of the specified period (assuming the system
* clock underlying <tt>Object.wait(long)</tt> is accurate). As a
* consequence of the above, if the scheduled first time is in the past,
* it is scheduled for immediate execution.
*
* <p>Fixed-delay execution is appropriate for recurring activities
* that require "smoothness." In other words, it is appropriate for
* activities where it is more important to keep the frequency accurate
* in the short run than in the long run. This includes most animation
* tasks, such as blinking a cursor at regular intervals. It also includes
* tasks wherein regular activity is performed in response to human
* input, such as automatically repeating a character as long as a key
* is held down.
*
* @param task task to be scheduled.
* @param firstTime First time at which task is to be executed.
* @param period time in milliseconds between successive task executions.
* @throws IllegalArgumentException if {@code firstTime.getTime() < 0}, or
* {@code period <= 0}
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} or {@code firstTime} is null
*/
//我们常见的调度task的api方法之一,指定调度的TimerTask,第一次执行的时刻,重复执行的时间间隔多少毫秒,
public void schedule(TimerTask task, Date firstTime, long period) {
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, firstTime.getTime(), -period);
}
/**
* Schedules the specified task for repeated <i>fixed-rate execution</i>,
* beginning after the specified delay. Subsequent executions take place
* at approximately regular intervals, separated by the specified period.
*
* <p>In fixed-rate execution, each execution is scheduled relative to the
* scheduled execution time of the initial execution. If an execution is
* delayed for any reason (such as garbage collection or other background
* activity), two or more executions will occur in rapid succession to
* "catch up." In the long run, the frequency of execution will be
* exactly the reciprocal of the specified period (assuming the system
* clock underlying <tt>Object.wait(long)</tt> is accurate).
*
* <p>Fixed-rate execution is appropriate for recurring activities that
* are sensitive to <i>absolute</i> time, such as ringing a chime every
* hour on the hour, or running scheduled maintenance every day at a
* particular time. It is also appropriate for recurring activities
* where the total time to perform a fixed number of executions is
* important, such as a countdown timer that ticks once every second for
* ten seconds. Finally, fixed-rate execution is appropriate for
* scheduling multiple repeating timer tasks that must remain synchronized
* with respect to one another.
*
* @param task task to be scheduled.
* @param delay delay in milliseconds before task is to be executed.
* @param period time in milliseconds between successive task executions.
* @throws IllegalArgumentException if {@code delay < 0}, or
* {@code delay + System.currentTimeMillis() < 0}, or
* {@code period <= 0}
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} is null
*/
//我们常见的调度task的api方法之一,并且带fix修正。指定调度的TimerTask,延迟多少毫秒执行,重复执行的时间间隔多少毫秒,
//带fix修正的意思是这样的,假如设定首次执行时间在当前时间之前,那么会计算出从开始时间到当前时间,按照period的间隔应该执行多少次任务,会把这么多次任务都执行完,相当于不遗漏,然后下一次任务执行的时间是最近一次任务应该执行的时间+执行周期,比如,timer在1:18分的时候调度一个首次执行时间在1:00的任务,间隔是5分钟执行一次,那么,task会执行1:00、1:05、1:10、1:15四次任务,然后到1:20的时候回继续执行,后面恢复正常。 没有fix的,在1:18分启动,只会执行一次,然后到1:23分的时候在执行第二次。
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.");
//此处可以看到,带有fix修正的调度,period值为正值
sched(task, System.currentTimeMillis()+delay, period);
}
/**
* Schedules the specified task for repeated <i>fixed-rate execution</i>,
* beginning at the specified time. Subsequent executions take place at
* approximately regular intervals, separated by the specified period.
*
* <p>In fixed-rate execution, each execution is scheduled relative to the
* scheduled execution time of the initial execution. If an execution is
* delayed for any reason (such as garbage collection or other background
* activity), two or more executions will occur in rapid succession to
* "catch up." In the long run, the frequency of execution will be
* exactly the reciprocal of the specified period (assuming the system
* clock underlying <tt>Object.wait(long)</tt> is accurate). As a
* consequence of the above, if the scheduled first time is in the past,
* then any "missed" executions will be scheduled for immediate "catch up"
* execution.
*
* <p>Fixed-rate execution is appropriate for recurring activities that
* are sensitive to <i>absolute</i> time, such as ringing a chime every
* hour on the hour, or running scheduled maintenance every day at a
* particular time. It is also appropriate for recurring activities
* where the total time to perform a fixed number of executions is
* important, such as a countdown timer that ticks once every second for
* ten seconds. Finally, fixed-rate execution is appropriate for
* scheduling multiple repeating timer tasks that must remain synchronized
* with respect to one another.
*
* @param task task to be scheduled.
* @param firstTime First time at which task is to be executed.
* @param period time in milliseconds between successive task executions.
* @throws IllegalArgumentException if {@code firstTime.getTime() < 0} or
* {@code period <= 0}
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} or {@code firstTime} is null
*/
/我们常见的调度task的api方法之一,并且带fix修正。指定调度的TimerTask,任务开始时间,重复执行的时间间隔多少毫秒,
public void scheduleAtFixedRate(TimerTask task, Date firstTime,
long period) {
if (period <= 0)
throw new IllegalArgumentException("Non-positive period.");
sched(task, firstTime.getTime(), period);
}
/**
* Schedule the specified timer task for execution at the specified
* time with the specified period, in milliseconds. If period is
* positive, the task is scheduled for repeated execution; if period is
* zero, the task is scheduled for one-time execution. Time is specified
* in Date.getTime() format. This method checks timer state, task state,
* and initial execution time, but not period.
*
* @throws IllegalArgumentException if <tt>time</tt> is negative.
* @throws IllegalStateException if task was already scheduled or
* cancelled, timer was cancelled, or timer thread terminated.
* @throws NullPointerException if {@code task} is null
*/
//无论哪种调度任务的api方法,最终都是用这个方法来进行调度的,只不过传递了不同的参数。
private void sched(TimerTask task, long time, long period) {
if (time < 0)
throw new IllegalArgumentException("Illegal execution time.");
// Constrain value of period sufficiently to prevent numeric
// overflow while still being effectively infinitely large.
//这里是为了防止设置的period太大,如果绝对值大于最大的long值的一半,就把period右移一位,缩小period的范围,防止在后期进行运算的时候移除。
if (Math.abs(period) > (Long.MAX_VALUE >> 1))
period >>= 1;
//任务队列同步
synchronized(queue) {
//如果timer线程不可以调度新任务了,就抛出异常,有一些情况会设置newTasksMayBeScheduled的值为false,后面可以看到。
if (!thread.newTasksMayBeScheduled)
throw new IllegalStateException("Timer already cancelled.");
//操作task设置信息,和内部操作同步。
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;
}
//将task放入队列
queue.add(task);
//这里的意思是如果当前调度的这个任务排在队列的头部,就唤醒当前队列wait的线程。
if (queue.getMin() == task)
queue.notify();
}
}
/**
* Terminates this timer, discarding any currently scheduled tasks.
* Does not interfere with a currently executing task (if it exists).
* Once a timer has been terminated, its execution thread terminates
* gracefully, and no more tasks may be scheduled on it.
*
* <p>Note that calling this method from within the run method of a
* timer task that was invoked by this timer absolutely guarantees that
* the ongoing task execution is the last task execution that will ever
* be performed by this timer.
*
* <p>This method may be called repeatedly; the second and subsequent
* calls have no effect.
*/
//取消timer,跟前面finalize的方差不多,设定timer线程不能调度新任务,清空队列,并且唤醒等待的timer线程,因为timer线程在执行任务时,如果队列为空会wait,
public void cancel() {
synchronized(queue) {
thread.newTasksMayBeScheduled = false;
queue.clear();
queue.notify(); // In case queue was already empty.
}
}
/**
* Removes all cancelled tasks from this timer's task queue. <i>Calling
* this method has no effect on the behavior of the timer</i>, but
* eliminates the references to the cancelled tasks from the queue.
* If there are no external references to these tasks, they become
* eligible for garbage collection.
*
* <p>Most programs will have no need to call this method.
* It is designed for use by the rare application that cancels a large
* number of tasks. Calling this method trades time for space: the
* runtime of the method may be proportional to n + c log n, where n
* is the number of tasks in the queue and c is the number of cancelled
* tasks.
*
* <p>Note that it is permissible to call this method from within a
* a task scheduled on this timer.
*
* @return the number of tasks removed from the queue.
* @since 1.5
*/
//清除队列中已经被取消的任务,并计数返回,如果有被取消的任务,把任务队列重新堆化,相当于按照下一次执行时间重新排个序,把最近的时间排到最前面
public int purge() {
int result = 0;
synchronized(queue) {
for (int i = queue.size(); i > 0; i--) {
if (queue.get(i).state == TimerTask.CANCELLED) {
queue.quickRemove(i);
result++;
}
}
if (result != 0)
queue.heapify();
}
return result;
}
}
/**
* This "helper class" implements the timer's task execution thread, which
* waits for tasks on the timer queue, executions them when they fire,
* reschedules repeating tasks, and removes cancelled tasks and spent
* non-repeating tasks from the queue.
*/
//timer线程,继承自Thread类,用来调度执行timertask
class TimerThread extends Thread {
/**
* This flag is set to false by the reaper to inform us that there
* are no more live references to our Timer object. Once this flag
* is true and there are no more tasks in our queue, there is no
* work left for us to do, so we terminate gracefully. Note that
* this field is protected by queue's monitor!
*/
//这就是我们前面经常看到的那个标记,默认为true
boolean newTasksMayBeScheduled = true;
/**
* Our Timer's queue. We store this reference in preference to
* a reference to the Timer so the reference graph remains acyclic.
* Otherwise, the Timer would never be garbage-collected and this
* thread would never go away.
*/
//使用任务队列作为参数来实例化
private TaskQueue queue;
TimerThread(TaskQueue queue) {
this.queue = queue;
}
//线程执行体,可以看到,这是一个循环,一旦出异常,newTasksMayBeScheduled被置为false,任务队列被清空。也就是说只要有一个任务出异常了,所有的任务就都终止了。
public void run() {
try {
mainLoop();
} finally {
// Someone killed this Thread, behave as if Timer cancelled
synchronized(queue) {
newTasksMayBeScheduled = false;
queue.clear(); // Eliminate obsolete references
}
}
}
/**
* The main timer loop. (See class comment.)
*/
//循环体,死循环,
private void mainLoop() {
while (true) {
try {
TimerTask task; //要调度执行的任务
boolean taskFired;//是否触发任务
synchronized(queue) {//锁定queue
// Wait for queue to become non-empty
while (queue.isEmpty() && newTasksMayBeScheduled)//如果队列是空的,并且可以调度新任务,那么就等待,在添加新任务的时候会被唤醒。
queue.wait();
if (queue.isEmpty())//如果唤醒之后,队列还是为空,就退出循环,一般是timer被取消
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) {//锁定task,判断状态,如果该任务时被取消的,就移除该任务,并继续下一次循环。
if (task.state == TimerTask.CANCELLED) {
queue.removeMin();
continue; // No action required, poll queue again
}
currentTime = System.currentTimeMillis();//获取当前时间
executionTime = task.nextExecutionTime;//获取任务的下一次执行时间
if (taskFired = (executionTime<=currentTime)) {//根据两个时间来判断是否可以执行该任务。
if (task.period == 0) { // Non-repeating, remove 如果period为0,为单次任务,从队列中移除,并设置任务状态为已执行。
queue.removeMin();
task.state = TimerTask.EXECUTED;
} else { // Repeating task, reschedule 周期性任务,重新排列任务队列,并设置该任务下一次的执行时间,如果是period小于0,就用当前时间加上间隔周期,如果period大于0,就用执行时间加上间隔周期。所以任务是不是fixRate的,是在这里进行处理的,主要是靠处理下一次的执行时间。由于是单线程执行,不是fixRate的可能会出现不能及时被执行,导致任务制定会被后延。
queue.rescheduleMin(
task.period<0 ? currentTime - task.period
: executionTime + task.period);
}
}
}
if (!taskFired) // Task hasn't yet fired; wait 如果任务没到触发时间,就wait这个时间差。
queue.wait(executionTime - currentTime);
}
if (taskFired) // Task fired; run it, holding no locks 如果任务该触发了,就使用run方法去执行timer的task,在当前主线程中执行。
task.run();
} catch(InterruptedException e) {
}
}
}
}
/**
* This class represents a timer task queue: a priority queue of TimerTasks,
* ordered on nextExecutionTime. Each Timer object has one of these, which it
* shares with its TimerThread. Internally this class uses a heap, which
* offers log(n) performance for the add, removeMin and rescheduleMin
* operations, and constant time performance for the getMin operation.
*/
//任务队列
class TaskQueue {
/**
* Priority queue represented as a balanced binary heap: the two children
* of queue[n] are queue[2*n] and queue[2*n+1]. The priority queue is
* ordered on the nextExecutionTime field: The TimerTask with the lowest
* nextExecutionTime is in queue[1] (assuming the queue is nonempty). For
* each node n in the heap, and each descendant of n, d,
* n.nextExecutionTime <= d.nextExecutionTime.
*/
//初始128长度的timertask数组,索引是从1开始的
private TimerTask[] queue = new TimerTask[128];
/**
* The number of tasks in the priority queue. (The tasks are stored in
* queue[1] up to queue[size]).
*/
//队列中的元素数量,
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.
*/
//向队列里面添加一个任务
void add(TimerTask task) {
// Grow backing store if necessary
if (size + 1 == queue.length)//=数组的扩容
queue = Arrays.copyOf(queue, 2*queue.length);
//将任务放在队列尾部
queue[++size] = task;
fixUp(size);//排除执行时间最早的元素
}
/**
* Return the "head task" of the priority queue. (The head task is an
* task with the lowest nextExecutionTime.)
*/
//获取队列最开头的元素,也就是最早执行时间的
TimerTask getMin() {//
return queue[1];
}
/**
* Return the ith task in the priority queue, where i ranges from 1 (the
* head task, which is returned by getMin) to the number of tasks on the
* queue, inclusive.
*/
//获取指定位置的任务
TimerTask get(int i) {
return queue[i];
}
/**
* Remove the head task from the priority queue.
*/
//移除队列头部的元素,这里是用了将尾部的元素给头部,尾部设定为null,交换之后头部的任务时间不一定最靠前,需要往后移动交换
void removeMin() {
queue[1] = queue[size];
queue[size--] = null; // Drop extra reference to prevent memory leak
fixDown(1);
}
/**
* Removes the ith element from queue without regard for maintaining
* the heap invariant. Recall that queue is one-based, so
* 1 <= i <= size.
*/
//移除哪里的,就把尾部的交换过去。
void quickRemove(int i) {
assert i <= size;
queue[i] = queue[size];
queue[size--] = null; // Drop extra ref to prevent memory leak
}
/**
* Sets the nextExecutionTime associated with the head task to the
* specified value, and adjusts priority queue accordingly.
*/
//将当前头部节点的下次执行时间进行调整,调整之后头部的任务时间不一定最靠前,需要往后移动交换,任务被触发后会被调用该方法
void rescheduleMin(long newTime) {
queue[1].nextExecutionTime = newTime;
fixDown(1);
}
/**
* Returns true if the priority queue contains no elements.
*/
//队列是否是空的
boolean isEmpty() {
return size==0;
}
/**
* Removes all elements from the priority queue.
*/
//清除任务队列
void clear() {
// Null out task references to prevent memory leak
for (int i=1; i<=size; i++)
queue[i] = null;
size = 0;
}
/**
* Establishes the heap invariant (described above) assuming the heap
* satisfies the invariant except possibly for the leaf-node indexed by k
* (which may have a nextExecutionTime less than its parent's).
*
* This method functions by "promoting" queue[k] up the hierarchy
* (by swapping it with its parent) repeatedly until queue[k]'s
* nextExecutionTime is greater than or equal to that of its parent.
*/
//这个还是比较核心的了,将最小的移动到头部,这个方法只在添加任务的时候调用了,添加时节点被添加到尾部,使用折半的方式,与新添加的任务对比时间,直到队列前段的任务时间比新添加的时间要要或者新添加的元素时间最早且被交换到最头部位置。
private void fixUp(int k) {
while (k > 1) {
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;
}
}
/**
* Establishes the heap invariant (described above) in the subtree
* rooted at k, which is assumed to satisfy the heap invariant except
* possibly for node k itself (which may have a nextExecutionTime greater
* than its children's).
*
* This method functions by "demoting" queue[k] down the hierarchy
* (by swapping it with its smaller child) repeatedly until queue[k]'s
* nextExecutionTime is less than or equal to those of its children.
*/
//这个也是比较核心的了,将最大的移动到尾部,。
private void fixDown(int k) {
int j;
while ((j = k << 1) <= size && j > 0) {
if (j < size &&
queue[j].nextExecutionTime > queue[j+1].nextExecutionTime)
j++; // j indexes smallest kid
if (queue[k].nextExecutionTime <= queue[j].nextExecutionTime)
break;
TimerTask tmp = queue[j]; queue[j] = queue[k]; queue[k] = tmp;
k = j;
}
}
/**
* Establishes the heap invariant (described above) in the entire tree,
* assuming nothing about the order of the elements prior to the call.
*/
//清除大量元素后重新堆化排序,由于fixDown是向后半段比较,此处使用前半段的索引即可,减少操作次数,降低时间复杂度,
void heapify() {
for (int i = size/2; i >= 1; i--)
fixDown(i);
}
}