Java introduced the Timer utility class in version 1.3, which is an ancient Timer used with TimerTask and TaskQueue. Starting from the Java 5 in in the process of contract awarding and introduces another Timer ScheduledThreadPoolExecutor, it for the Timer to do a lot of improvement and provide more tools, can be thought of as replace of the Timer.

So why introduce the Timer utility class? By understanding the Timer function and the principle behind it, will help us better understand ScheduledThreadPoolExecutor contrast, at the same time, ScheduledThreadPoolExecutor some improvement ideas in our usual coding can also draw lessons from.

Primary member variable

There are two main member variables used in Timer:

  1. TaskQueue: A time-prioritized queue where the time is the number of milliseconds in which each scheduled task will be executed next (as of January 1, 1970)
  2. TimerThread: Orchestrates and triggers execution of timed tasks in a TaskQueue, which is an internal thread with an infinite loop.
Private final TaskQueue queue = new TaskQueue(); Private final TimerThread thread = new TimerThread(queue); private final TimerThread = new TimerThread(queue); Public Timer(String name) {thread.setName(name); thread.start(); }Copy the code

Timing function

Timer provides three timing modes:

  1. One-off task
  2. Execution at fixed delay
  3. Execute at a fixed rate

The first is easier to understand, where the task is performed only once; For the first, Timer provides the following two methods:

Public void schedule(TimerTask task, long delay) {public void schedule(TimerTask task, long delay) {... } public void schedule(TimerTask task, Date time) {... }Copy the code

The second Fixed Delay mode also provides the following two methods

Public void schedule(TimerTask task, long delay, long period) {// Delay starts from the current time. Delay starts from the current time. Public void schedule(TimerTask task, Date firstTime, long period){... }Copy the code

Here’s how it works:

The first execution will be performed at the specified point in time (if the TimerThread is not performing any other tasks at this time). If other tasks are executing, they will be executed until the other tasks have completed.

Starting from the second time, the execution time of each task is the start time of the last task plus the specified period number of milliseconds.

So how do we understand that? Let’s look at the code, right

public static void main(String[] args) { TimerTask task1 = new DemoTimerTask("Task1"); TimerTask task2 = new DemoTimerTask("Task2"); Timer timer = new Timer(); timer.schedule(task1, 1000, 5000); timer.schedule(task2, 1000, 5000); } static class DemoTimerTask extends TimerTask { private String taskName; private DateFormat df = new SimpleDateFormat("HH:mm:ss---"); public DemoTimerTask(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println(df.format(new Date()) + taskName + " is working."); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(df.format(new Date()) + taskName + " finished work."); }}Copy the code

Task1 and task2 are two tasks executed at the same time, and each task takes 2 seconds to execute. If we left the sixth line blank, we would get the following result (same as the third Fixed Rate) :

13:42:58---Task1 is working.
13:43:00---Task1 finished work.
13:43:03---Task1 is working.
13:43:05---Task1 finished work.
13:43:08---Task1 is working.
13:43:10---Task1 finished work.
Copy the code

If you open the sixth row, let’s look at the execution of the two tasks. The TimerThread is a single thread, and the execution of each scheduled task is completed in this thread. If multiple tasks need to be executed at the same time, the execution will be blocked. This results in Task2’s second execution time being its previous execution time (13:43:57) plus 5 seconds (13:44:02).

13:43:55---Task1 is working.
13:43:57---Task1 finished work.
13:43:57---Task2 is working.
13:43:59---Task2 finished work.
13:44:00---Task1 is working.
13:44:02---Task1 finished work.
13:44:02---Task2 is working.
13:44:04---Task2 finished work.
Copy the code

What if Task3 was executed at the same time and interval?

The conclusion is that the queue will also be queued, and the execution time depends on two factors:

1. Time of the last execution

2. Is there any other task running at the expected execution time? If there is, you can only queue up


Let’s look at the third Fixed Rate mode and modify the above code slightly:

public static void main(String[] args) { TimerTask task1 = new DemoTimerTask("Task1"); TimerTask task2 = new DemoTimerTask("Task2"); Timer timer = new Timer(); timer.scheduleAtFixedRate(task1, 1000, 5000); timer.scheduleAtFixedRate(task2, 1000, 5000); } static class DemoTimerTask extends TimerTask { private String taskName; private DateFormat df = new SimpleDateFormat("HH:mm:ss---"); public DemoTimerTask(String taskName) { this.taskName = taskName; } @Override public void run() { System.out.println(df.format(new Date()) + taskName + " is working."); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(df.format(new Date()) + taskName + " finished work."); }}Copy the code

Task1 and Task2 perform tasks at the same time and in the same cycle. We expect Task1 to perform tasks at the same time every 5 seconds. 14:21:47-14:21:52-14:21:57-14:22:02-14:22:07, actually it can be executed periodically alternately because Task2 is also executed periodically, The TaskQueue locks are held alternately (this will be discussed in the next section of TimerThread).

14:21:47---Task1 is working.
14:21:49---Task1 finished work.
14:21:49---Task2 is working.
14:21:51---Task2 finished work.
14:21:52---Task2 is working.
14:21:54---Task2 finished work.
14:21:54---Task1 is working.
14:21:56---Task1 finished work.
14:21:57---Task1 is working.
14:21:59---Task1 finished work.
14:21:59---Task2 is working.
14:22:01---Task2 finished work.
Copy the code

TimerThread

Above we mainly talked about some of the main source code of Timer and timing mode, let’s analyze the timing task thread supporting Timer TimerThread.

The flowchart of TimerThread is as follows:

TimerThread process

Source code interpretation is as follows:

private void mainLoop() { while (true) { try { TimerTask task; boolean taskFired; Synchronized (queue) {// If there is no task in the queue to execute, While (queue.isempty () && newTasksMayBeScheduled) queue.wait(); If (queue.isempty ()) break; if (queue.isempty ()) break; long currentTime, executionTime; Task = queue.getmin (); 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; // taskFired indicates whether the thread needs to be executed immediately, If (taskFired = (executionTime<=currentTime)) {//task.period==0 means that the task only needs to be executed once, If (task.period == 0) {queue.removemin (); task.state = TimerTask.EXECUTED; } else {// Repeating task, reschedule // for tasks whose task.period is not equal to 0, Period <0 indicates tasks in fixed delay mode. // Task. period>0 indicates tasks in fixed rate mode. Queue. currentTime - task.period : executionTime + task.period); }}} // Suspend TimerThread executionTime-currentTime in milliseconds and activate if (! taskFired) queue.wait(executionTime - currentTime); } // If the next execution time of the task is up, execute the task // Note: If (taskFired) // There is no try catch exception. When the TimerTask throws an exception, the entire TimerThread will break out of the loop. Task.run (); } catch(InterruptedException e) { } } }Copy the code

conclusion

Through the above analysis, we can draw the following conclusions:

  1. Timer Supports three modes of scheduled tasks (one-time task, Fixed Delay mode, and Fixed Rate mode).
  2. The TimerThread in Timer works in single-thread mode. As a result, all scheduled tasks cannot be executed at the same time and may be delayed
  3. The TimerThread does not handle the exception of the task, so each implementation of the TimerTask must try catch itself to prevent the exception from being thrown, causing the Timer to fail as a whole

Demo code location


SRC/main/Java/net/weichitech/util/TimerFixedDelayDemo. Java, small western/Java programming – learning – Gitee.com


SRC/main/Java/net/weichitech/util/TimerFixedRateDemo. Java, small western/Java programming – learning – Gitee.com