[Source code] source code analysis of Timer and TimerTask

Source: Internet
Author: User
Timer is a tool class in the java. util package and provides the Timer function. We can construct a Timer object and call its schedule method to execute a specific task after a specific time or delay, you can even keep a task running at a specific frequency. this task is described by TimerTask. we can write the required operations in the run method of the TimerTask class. Timer is a tool class in the java. util package and provides the Timer function. We can construct a Timer object and call its schedule method to execute a specific task after a specific time or delay, you can even keep a task running at a specific frequency. this task is described by TimerTask. we can write the required operations in the run method of the TimerTask class. I decided to study the source code of this class based on the mentality of "knowing what it is, knowing why it is so.

Open the source code of the Timer class and I found two member variables:

/*** The timer task queue. this data structure is shared with the timer * thread. the timer produces tasks, via its varous schedule cils, * and the timer thread consumes, executing timer tasks as appropriate, * and removing them from the queue when they're obsolete. */private final TaskQueue queue = new TaskQueue (); // task queue/*** The timer thread. */private final TimerThread thread = new TimerThread (queue); // execution thread

TaskQueue is a priority queue that stores the TimerTask objects to be executed. TimerTask objects are added to the queue through a series of schedule methods in the Timer class. TimerThread is responsible for constantly extracting tasks in the TaskQueue, then execute it. that is to say, all tasks are executed in sub-threads. The TaskQueue queue is sorted by the next execution time. TimerThread extracts the TimerTask that needs to be executed first each time. (Similar to the Handler mechanism in android ~)The biggest difference between a priority queue and a normal queue is that each time a priority queue leaves the queue, it is not in the first-in-first-out mode. Here The implementation of priority queue uses the heap structure.(Of course, you can also use a common linked list, but it is not cost-effective to search for the element with the highest priority in an O (n) time traversal chain table ), the insert and update operations can be maintained at O (logn ):
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. nextExecu TionTime. */private TimerTask [] queue = new TimerTask [128]; // use an array to store heap elements. The maximum value is 128/*** the number of tasks in The priority queue. (The tasks are stored in * queue [1] up to queue [size]). */private int size = 0; // number of tasks/*** 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) {// add the TimerTask task to this queue/ /Grow backing store if necessary if (size + 1 = queue. length) queue = Arrays. copyOf (queue, 2 * queue. length); queue [++ size] = task; fixUp (size ); // Adjust the heap structure ----> so-called filtering}/*** Return the "head task" of the priority queue. (The head task is an * task with the lowest nextExecutionTime .) */TimerTask getMin () {// the element with the highest priority always returns queue [1] At the first position;}/*** return the ith task in the priority queue, where I ra Nges from 1 (the * head task, which is returned by getMin) to the number of tasks on the * queue, volume sive. */TimerTask get (int I) {return queue [I];}/*** Remove the head task from the priority queue. */void removeMin () {queue [1] = queue [size]; queue [size --] = null; // Drop extra reference to prevent memory leak fixDown (1 ); // Adjust the heap structure -----> so-called downstream filter}/*** Removes the ith element from queue withou T 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 abve) assuming The heap * satisfies the invariant failed t 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 abve) in the subtree * rooted at k, which is assumed to satisfy the heap invariant variable t * possibly for node k itself (which may have a nextExecutionTime greater * than its children's ). ** This metho D 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]. nextExecu TionTime <= queue [j]. nextExecutionTime) break; TimerTask tmp = queue [j]; queue [j] = queue [k]; queue [k] = tmp; k = j ;}} /*** Establishes the heap invariant (described abve) in the entire tree, * assuming nothing about the order of the elements prior to the call. */void heapify () {// heap creation operation, starting from the first non-leaf node. For (int I = size/2; I> = 1; I --) fixDown (I );}}

TaskQueue is an internal TimerTask array. array elements start from 1. this array is called a heap. it is also a small top heap. the top element of the heap is always the first element, each time TimerTask is added, the fixup filtering operation is called to maintain the heap features. after each element is deleted, the fixdown filtering operation must be called to maintain the heap features. Heapify is a heap building function (similar to heap building operations in heap sorting), starting from the first non-leaf node.
After learning about TaskQueue, let's look at the TimerThread class:
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! */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 wowould never be garbage-collected and this * thread wowould never go away. */private TaskQueue queue; // hold the reference TimerThread (TaskQueue queue) {this. queue = queue;} public void run () {try {mainLoop ();/ /Execute an endless loop, constantly retrieve and execute tasks from the queue, blocking if no task exists} finally {// Someone killed this Thread, behave as if Timer canceled synchronized (queue) {newTasksMayBeScheduled = false; queue. clear (); // Eliminate obsolete references }}/ *** The main timer loop. (See class comment .) */private void mainLoop () {while (true) {// endless loop try {TimerTask task; boolean taskFired; synchronized (queue) {// thread security // Wait for queue to B Ecome non-empty while (queue. isEmpty () & newTasksMayBeScheduled) // queue when no task exists. wait (); // wait for 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 (); // retrieves the synchronized (task. lock) {if (task. state = TimerTask. CANCELLED) {// The task is canceled. removeMin (); // kill this task conti Nue; // No action required, poll queue again} currentTime = System. currentTimeMillis (); executionTime = task. nextExecutionTime; if (taskFired = (executionTime <= currentTime) {// whether the task has been executed if (task. period = 0) {// Non-repeating, remove queue. removeMin (); // executed tasks are removed from the queue. 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); // wait for a long time before execution} if (taskFired) // Task fired; run it, holding no locks task. run (); // execute this task} catch (InterruptedException e ){}}}}

Note: TimerThread will call the mainloop method in the run method, which is an endless loop. The task is continuously retrieved from the task queue and executed. If no task can be executed, wait until the queue is not empty, and the schedule method of the Timer class will call notify to wake up the thread and execute the task.

Private void sched (TimerTask task, long time, long period) {// All schedule methods call this method if (time <0) throw new IllegalArgumentException ("Illegal execution time. "); // Constrain value of period sufficiently to prevent numeric // overflow while still being interval tively infinitely large. if (Math. abs (period)> (Long. MAX_VALUE> 1) period> = 1; synchronized (queue) {if (! Thread. newTasksMayBeScheduled) throw new IllegalStateException ("Timer already canceled."); synchronized (task. lock) {if (task. state! = TimerTask. VIRGIN) throw new IllegalStateException ("Task already scheduled or canceled"); task. nextExecutionTime = time; task. period = period; task. state = TimerTask. SCHEDULED;} queue. add (task); // add the task queue if (queue. getMin () = task) queue. Y (); // wake up the task execution thread }}

So when is TimerThread started? You can also guess it. it must have been executed when Timer was created:

Public Timer (String name) {thread. setName (name); thread. start (); // start thread}

After the execution of the main thread is complete, the Timer thread may still be in the blocking or other state. sometimes this is not what we want to see. the Timer class has such a constructor, the task execution thread can run in the form of a daemon thread, so that when the main thread completes execution, the Daemon thread will also stop.
 public Timer(boolean isDaemon) {        this("Timer-" + serialNumber(), isDaemon);    }

The above is the source code analysis process of the Timer class, and a figure is attached to help you understand:


Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.