Java. util. Timer, java. util. timer

Source: Internet
Author: User

Java. util. Timer, java. util. timer

Timer is used to manage delayed or periodic tasks executed in the background. The tasks are represented by java. util. TimerTask. The task can be executed in two ways:

  • Run at a fixed rate: Two overload methods of scheduleAtFixedRate
  • Execution by fixed delay: Four overload methods of schedule

The specific differences will be detailed later.

To implement a scheduled task, you only need to implement the run method of TimerTask. Each task has the next execution time nextExecutionTime (millisecond). If it is a periodic task, the next execution time is updated each time. When nextExecutionTime is earlier than the current time, will execute it.

I. Usage

The specific usage of Timer is very simple, for example:

        Timer timer = new Timer();        timer.schedule(new TimerTask() {            @Override            public void run() {                System.out.println("Timer is running");            }        }, 2000);
The scheduled task is executed only once in 2 seconds. You can also execute periodic tasks by adding the third parameter period of schedule, for example:

        Timer timer = new Timer();        timer. scheduleAtFixedRate(new TimerTask() {            @Override            public void run() {                System.out.println("Timer is running");            }        }, 2000, 5000);
It indicates that the task starts to run in 2 seconds and then runs every 5 seconds.

II. Implementation Analysis

For each Timer, only one thread is used in the background to execute all tasks. All tasks are saved to a task queue java. util. in TaskQueue, it is an internal class of Timer. This is a priority queue, and the algorithm used is binary min heap ).

Timer's document says:

After the last live reference to a Timer object goes away and all outstanding tasks have completed execution, the timer's task execution thread terminates gracefully (and becomes subject to garbage collection ).

(Not fully translated according to the original article): When all the tasks in the task queue are completed, that is, there is no one-time task, there is no periodic task, then, the background thread of Timer will be elegantly terminated and become the object of garbage collection.

However, during the test, it was found that after a one-time task is executed, the task thread does not stop, but is always blocked. I don't know why. JDK 1.7.0 _ 79 is used.

Use jstack to view the thread status as follows:

"Timer-0" prio=5 tid=0x00007ff184046000 nid=0x5807 in Object.wait() [0x000000011ebea000]   java.lang.Thread.State: WAITING (on object monitor)at java.lang.Object.wait(Native Method)- waiting on <0x00000007ab1bbea0> (a java.util.TaskQueue)at java.lang.Object.wait(Object.java:503)at java.util.TimerThread.mainLoop(Timer.java:526)- locked <0x00000007ab1bbea0> (a java.util.TaskQueue)at java.util.TimerThread.run(Timer.java:505)

The thread processing blocking status of the Timer task is displayed.

A TimerTask has four states:

  • VIRGIN: the status of the newly created task, indicating that the task has not been scheduled.
  • SCHEDULED: SCHEDULED execution. For non-periodic tasks, it indicates that the task has not been executed. When the task is added to the task execution queue, it is called Timer. schedule.
  • EXECUTED: indicates that the non-periodic task has been EXECUTED or is being EXECUTED and has not been canceled.
  • CANCELLED: indicates that the task has been canceled. After the cancel method is called, the task in this status is removed from the queue during each execution.

Next, let's take a look at what happens when Timer. schedule is called. All calls to Timer. schedule are called by a private method sched.

For example, delayed tasks (non-periodic tasks ):

Public void schedule (TimerTask task, long delay) {// The latency cannot be less than 0 if (delay <0) throw new IllegalArgumentException ("Negative delay. "); // call the private sched method. Note that the execution time here is absolute time, while the period is 0, indicating that the periodic task sched (task, System. currentTimeMillis () + delay, 0);} 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 into tively infinitely large. if (Math. abs (period)> (Long. MAX_VALUE> 1) period> = 1; synchronized (queue) {// if the timer has been canceled, no more tasks can be executed, so an exception if (! Thread. newTasksMayBeScheduled) throw new IllegalStateException ("Timer already canceled. "); synchronized (task. lock) {// if the status of the task to be executed is not VIRGIN, an exception is thrown if (task. state! = TimerTask. VIRGIN) throw new IllegalStateException ("Task already scheduled or canceled"); // set the task execution time. Note that this time is the absolute time Task. nextExecutionTime = time; // you can specify the task execution cycle. period = period; // set the task status to SCHEDULED task. state = TimerTask. SCHEDULED;} // Add the task to the task queue and wait for the task execution thread to debug and execute the queue. add (task); // check whether the next task to be executed is the task currently added. if so, notify the background task thread if (queue. getMin () = task) queue. notify ();}}
The background thread for executing the task. Timer uses an internal class TimerThread. It has a newTasksMayBeScheduled attribute to indicate whether the task can be executed. The default value is true. It is set to false when the cancel method is called, you cannot add or execute tasks later. At the same time, it also holds a reference to the task queue of the task queue, rather than directly referencing the task queue of the Timer. This is because the Timer cannot be recycled due to cyclic reference, and the task thread cannot be terminated normally.

The following describes the implementation of the task thread:

    public void run() {        try {            mainLoop();        } finally {            // Someone killed this Thread, behave as if Timer cancelled            synchronized(queue) {                newTasksMayBeScheduled = false;                queue.clear();  // Eliminate obsolete references            }        }    }

Actually, the mainLoop method is called:

Private void mainLoop () {while (true) {try {TimerTask task; boolean taskFired; synchronized (queue) {// wait for the task queue to become non-empty, if the task queue is empty and the Timer is not canceled, the thread is blocked. Wait for the task queue to be empty. You can see that after each task is added, will notify this thread to check and execute the corresponding task 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 current Time, executionTime; // obtain the next task to be executed in the current task queue = queue. getMin (); synchronized (task. lock) {// if the task is canceled, remove the task from the queue and continue executing the next task if (task. state = TimerTask. CANCELLED) {queue. removeMin (); continue; // No action required, poll queue again} currentTime = System. currentTimeMillis (); executionTime = task. nextExecutionTime; // if the execution time of the current task is <= current time, the task is executed; otherwise, the task is not executed. You can also note that when adding a task, the execution time is a past time, And if (task Fired = (executionTime <= currentTime) {// if the task is not a non-periodic task, remove the task from the task queue and set the task status to EXECUTED if (task. period = 0) {// Non-repeating, remove queue. removeMin (); task. state = TimerTask. EXECUTED;} else {// Repeating task, reschedule // if it is a periodic task, reset the next execution time of the task. Here, note that period may be positive and negative queue. rescheduleMin (task. period <0? CurrentTime-task. period: executionTime + task. period) ;}}// if no task is to be executed, wait until the next task execution time if (! TaskFired) // Task hasn' t yet fired; wait queue. wait (executionTime-currentTime);} // how to execute a Task? Here, the logic of the task is actually executed if (taskFired) // Task fired; run it, holding no locks task. run () ;}catch (InterruptedException e ){}}}

The logic for resetting the next execution time of the task is as follows:

queue.rescheduleMin(task.period<0 ? currentTime   - task.period : executionTime + task.period);
Here, the task execution cycle can be positive and negative:

  • Positive number: indicates that the execution is scheduled at a fixed rate. For example, if the execution cycle is once every 5 seconds and the previous execution time is 20:51:30, the next execution time is 20:51:35, if the execution time of other tasks exceeds 5 seconds, for example, 15 seconds, this may cause the task to fail to be executed at the specified time, this destroys the task execution rate, but it will be executed three times in a row later.
  • Negative number: scheduled execution based on fixed latency. For example, the execution cycle is once every five seconds. Normally, for example, the execution time is 20:51:30, however, because it takes 8 seconds to execute other tasks, that is, when the current task is executed at 20:51:38, the next execution time will be postponed, that is, 20:51:43.

Iii. Timer Defects

1. Because there is only one thread for executing a task, if the execution time of a task is too long, the scheduled accuracy of other tasks will be compromised. For example, if a task is executed once every 1 second and another task takes 5 seconds to execute, the task will be executed five times in a row after the task is completed in five seconds, and the task with a fixed delay will be lost four times.

2. if an exception is thrown during execution of a task, the execution thread will terminate, and other tasks in Timer cannot be executed.

3. Timer uses absolute time, that is, a certain time point. Therefore, it depends on the system time. If the system time is modified, the task may not be executed.

4. Better alternatives

Because Timer has these defects, we can use ScheduledThreadPoolExecutor in JDK1.5 to replace it and Executors. newScheduledThreadPool factory method or use the ScheduledThreadPoolExecutor Constructor's constructor to create a scheduled task. It is implemented based on the thread pool and there is no problem with Timer. When the number of threads is 1, it is equivalent to Timer.

Copyright Disclaimer: This article is an original article by the blogger and cannot be reproduced without the permission of the blogger.

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.