1. The three dimensions of the Timer are first {@link Java.util.Timer}, which is the outermost class, which contains {@link java.util.TaskQueue}, which is stored {@link Java.util.TimerTask} queue--a priority queue of timertasks.
The second layer is {@link Java.util.TimerThread}, which is a thread that {@link Java.util.Timer} was created and started at initialization time, and this thread takes the task and executes it.
/** * 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 * @si NCE 1.5 * /Public Timer (String name) { thread.setname (name); Thread.Start (); }
A subclass of 2.TimerThreadThread that iterates through the task in the Run method.
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) {//Wait for the queue to become non-empty while (Queue.isempty () & amp;& newtasksmaybescheduled) queue.wait (); if (Queue.isempty ()) break; Queue is empty and would forever remain; Die//Queue nonempty; Look at first evt and does the right thing long currenttime, executiontime; task = Queue.getmin (); Synchronized (Task.lock) {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, RE Move queue.removemin (); Task.state = timertask.executed; } else {//repeating task, reschedule 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 (); } catch (Interruptedexception e) {} } }
3.task method of creating--schedule
public void Schedule (timertask task, long delay, long period) { if (Delay < 0) throw new Illegalargumentexcepti On ("negative delay."); if (period <= 0) throw new IllegalArgumentException ("non-positive period."); Sched (Task, System.currenttimemillis () +delay,-period); }
/** * Schedule The specified timer task for execution on the specified * time with the specified period, in Millis Econds. If period is * positive, the task was scheduled for repeated execution; If period is * zero, the task was scheduled for one-time execution. Time is specified * in Date.gettime () format. This method checks a timer state, a task state, a * and initial execution time, but not period. * * @throws illegalargumentexception if <tt>time</tt> is negative. * @throws IllegalStateException If task is already scheduled or * cancelled, timer was cancelled, or timer th Read terminated. * @throws nullpointerexception if {@code task} is null */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. 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 Illegalstateexce Ption ("Task already scheduled or cancelled"); Task.nextexecutiontime = time; Task.period = period; Task.state = timertask.scheduled; } queue.add (Task); if (queue.getmin () = = Task) queue.notify (); } }
1. Double lock, first lock queue, then lock Task,task with an object as lock
2. Set the next execution time for the TimerTask
{@link Java.util.timertask#nextexecutiontime} = System.currenttimemillis () +delay
3. Add a task to the queue
{@link Java.util.timer#queue}
4. The current task if it is a task in the queue, execute
Task = = {@link Java.util.taskqueue#getmin}, call the Notify method of the queue. If not, then there is a task waiting to be executed, just into the queue, without calling the Notify method.
5.{@link Java.util.timerthread#mainloop}
{@link Java.util.TimerThread} will be in {@link Java.util.Timer}
The Mainloop method is called when the construction is started.
At the beginning, the queue is empty, so queue.await (), the current thread hangs, and when the timer is added to the TimerTask task,
The Queue.notify () method is called to wake the Mainloop thread.
4. Reorder the heap according to Priority 1. TimerTask's in-heap (queue) operation delay time is set for long, that is, in order to let the task not execute, look at the queue comparison operation, period here is used as a flag bit, in the debug time as a marker to distinguish between different tasks, look at the sorting status.
Here are 3 examples, the first into the queue, the index is 1, the second into the queue, the index is 2,2>>1=1, and then take queue[2] and queue[1] compared to the next execution time, Queue[2] is earlier than queue[1, so the exchange order.
The third into the queue, index is 3,3>>1=1, and the first one than, Queue[3] is earlier than queue[1], so the order of exchange, so now queue[1] the first execution, queue[2] and queue[3] is not considered. The reorder operation for each incoming queue is performed in the {@link Java.util.taskqueue#fixup} method
/** * Establishes the heap invariant (described above) assuming the heap * satisfies the invariant except possibly For the leaf-node indexed by K * (which May has a nextexecutiontime less than its parent s). * * This method functions by ' promoting ' queue[k] up the Hierarchy * (by swapping it with its parent) repeatedly u Ntil Queue[k] ' s * nextexecutiontime is greater than or equal to that of the 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; } }
2.mainLoop execution: Each time the first task of the queue is taken, if the task has not yet reached the execution time, wait for the corresponding time queue.wait (Executiontime-currenttime).
if (!taskfired)//Task hasn ' t yet fired; Wait queue.wait (executiontime-currenttime);
If there is another task that has a higher priority (in the order of execution), call fixup to queue the current task to the queue header (higher priority), and then notify the queue to interrupt the wait and re-fetch the higher priority task.
/** * Adds A new task to the priority queue. * /Void Add (TimerTask Task) { //Grow backing store if necessary if (size + 1 = = queue.length) queue = Arr ays.copyof (queue, 2*queue.length); Queue[++size] = task; Fixup (size); }
If the execution time (wait end) is reached, the task is executed at the next loop. If the task is non-repeating, call removemin to remove the current task, Fixdown in Removemin, and make heap reordering. In the case of repetitive tasks, call Reschedulemin to set the next execution time, call Fixdown in Reschedulemin, and make heap reordering. 3.{@link Java.util.taskqueue#fixdown}
/** * establishes the heap invariant (described above) in the subtree * rooted at K, which are assumed to satisfy T He heap invariant except * Possibly for node K itself (which could have a nextexecutiontime greater * than it child Ren ' s). * * This method functions by "demoting" queue[k] down the hierarchy * (by swapping it with its smaller child) Repe atedly until Queue[k] ' s * nextexecutiontime are 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; } }
Reorder the remaining tasks and transfer the next execution time to the location of the first task.
Test Case:
public static void Test1 () { timer.schedule (new TimerTask () { @Override public void Run () { System.out.println ("Time ' up 1!---" + New Date (). toString ()); Sleeputil.sleep (30000); } }, * *, * +); Timer.schedule (New TimerTask () { @Override public void Run () { System.out.println ("Time's Up 2!---" + New Date (). ToString ()); Sleeputil.sleep (30000); } }, * *, * +); Timer.schedule (New TimerTask () { @Override public void Run () { System.out.println ("Time's up 3!---" + New Date ( ). ToString ()); Sleeputil.sleep (30000); } , 5 *, 333333 *); }
The execution order of the 5.TimerTask can be learned that the timer is a single thread executing task, and a timer object will only enable one timerthread. When a timer executes multiple tasks, if a task takes too long to execute, the time after which the task is executed may not be the time you expect it to execute, because a task is executed before the next task is executed.
Test Case:
public static void Test3 () { timer.schedule (new TimerTask () { @Override public void Run () { System.out.println ("Time ' up 1!---" + New Date (). toString ()); Sleeputil.sleep (0); } }, 0, 2 * +); Timer.schedule (New TimerTask () { @Override public void Run () { System.out.println ("Time's Up 2!---" + New Date (). ToString ()); Sleeputil.sleep (); } }, 0, 2 * +); Evictiontimer.schedule (evictor, delay, delay); }
TimerTask execution time is too long, over the period, the execution 5s,period is 2s, so period equivalent to failure. Because the time for the next execution is calculated like this,
{@link Java.util.timertask#nextexecutiontime} = System.currenttimemillis () +delay
Therefore, when this task execution is over (over 5s), it must have exceeded the time it was supposed to execute when the next task was taken out to determine the execution time. According to the logic in Mainloop, when the execution time is judged to be earlier than the current time, the task is executed directly.
Pool (iii)--timer