In our programming process, if we need to perform some simple timing tasks without complex control, we can consider using the Timer Timer task in JDK to achieve. The following LZ analyzes Java Timer from three aspects: its principle, instance and Timer defects.

A list,

In Java, a complete scheduled task needs to be completed by two classes: Timer and TimerTask. They are defined in the API as Timer: a tool that a thread uses to schedule tasks to be executed later in a background thread. Tasks can be scheduled to be executed once or repeated periodically. Tasks scheduled for one or repeated execution by TimerTask: Timer. TimerTask is an abstract class whose subclasses represent tasks that can be scheduled by a Timer.

1. The Timer class

In the Timer utility class, four constructors are provided. Each constructor starts a Timer thread, and the Timer class ensures that multiple threads can share a single Timer object without external synchronization, so the Timer class is thread-safe. But because each is a Timer object corresponding to a single background thread, for all the Timer task order, normally our thread consumed task execution time should be very short, but due to special circumstances a Timer task execution time is too long, then he will be “exclusive” Timer task executing thread, All subsequent threads must wait for it to complete, which delays the execution of subsequent tasks and causes them to pile up, as we’ll see later.

When the program initializes and completes the Timer, the scheduled task will be executed according to the time we set. Timer provides the schedule method, which has multiple overloaded methods to adapt to different situations, as follows:

Schedule (TimerTask Task, Date time) : Schedules the execution of a specified task at a specified time.

Schedule (TimerTask task, Date firstTime, long period) : To schedule the specified task to start repeating at a specified time with a fixed delay.

Schedule (TimerTask task, long delay) : Schedules the execution of the specified task after the specified delay.

Schedule (TimerTask task, long delay, long period) : schedules the specified task to be repeatedly executed with a fixed delay starting from the specified delay.

The scheduleAtFixedRate method is also overloaded. The scheduleAtFixedRate method is the same as schedule, but its emphasis is different.

ScheduleAtFixedRate (TimerTask task, Date firstTime, long period) : schedules the repeated execution of tasks at a fixed rate at a specified time.

ScheduleAtFixedRate (TimerTask task, long delay, long period) : schedules the repeated execution of tasks at a fixed rate after a specified delay.

2. TimerTask

The TimerTask class is an abstract class that is scheduled by the Timer to be executed once or repeatedly. It has an abstract method run() method that performs the actions to be performed by the corresponding timer task. So each concrete task class must inherit TimerTask and override the run() method.

It also has two non-abstract methods:

Boolean Cancel () : Cancel this timer task.

Long scheduledExecutionTime() : returns the last scheduledExecutionTime of this task.

Second, the instance

1. Specify a delay for executing scheduled tasks

public class TimerTest01 { Timer timer; public TimerTest01(int time){ timer = new Timer(); timer.schedule(new TimerTaskTest01(), time * 1000); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { System.out.println(</span>&quot; timer begin.... &quot; <span style="color: #000000">); </span><span style="color: #0000ff">new</span> TimerTest01(3<span style="color: #000000">); } } public class TimerTaskTest01 extends TimerTask{ </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; Time's up!!!! &quot; <span style="color: #000000">); }}Copy the code

Running results:

First print: timer begin…. Print after 3 seconds: Time’s up!!!!

2. Execute the scheduled task at the specified time

public class TimerTest02 { Timer timer; </span><span style="color: #0000ff">public</span><span style="color: #000000"> TimerTest02(){ Date time </span>=<span style="color: #000000"> getTime(); System.out.println(</span>&quot; Specify time= "time"; +<span style="color: #000000"> time); timer </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> Timer(); timer.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTaskTest02(), time); } </span><span style="color: #0000ff">public</span><span style="color: #000000"> Date getTime(){ Calendar calendar </span>=<span style="color: #000000"> Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, </span>11<span style="color: #000000">); calendar.set(Calendar.MINUTE, </span>39<span style="color: #000000">); calendar.set(Calendar.SECOND, </span>00<span style="color: #000000">); Date time </span>=<span style="color: #000000"> calendar.getTime(); </span><span style="color: #0000ff">return</span><span style="color: #000000"> time; } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { </span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTest02(); } } public class TimerTaskTest02 extends TimerTask{ @Override </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; Specify time to execute thread tasks... &quot; <span style="color: #000000">); }}Copy the code

The thread task will be executed when the time reaches 11:39:00, of course, it will be executed after the time!! The execution result is as follows:

Tue Jun 10 11:39:00 CST 2014 Tue Jun 10 11:39:00 CST 2014

3. Execute the scheduled task at the specified interval after the specified delay

public class TimerTest03 { Timer timer; </span><span style="color: #0000ff">public</span><span style="color: #000000"> TimerTest03(){ timer </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> Timer(); timer.schedule(</span><span style="color: #0000ff">new</span> TimerTaskTest03(), 1000, 2000<span style="color: # 000000 ">); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { </span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTest03(); } } public class TimerTaskTest03 extends TimerTask{ @Override </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { Date date </span>= <span style="color: #0000ff">new</span> Date(<span style="color: #0000ff">this</span><span style="color: #000000">.scheduledExecutionTime()); System.out.println(</span>&quot; The thread will be executed at this time. +<span style="color: #000000"> date); }}Copy the code

Running results:

Tue Jun 10 21:19:47 CST 2014 Tue Jun 10 21:19:49 CST 2014 Tue Jun 10 21:19:49 CST 2014 Tue Jun 10 21:19:51 CST 2014 Tue Jun 10 21:19:53 CST 2014 Tue Jun 10 21:19:53 CST 2014 Tue Jun 10 21:19:55 CST 2014 The time for executing this thread is: Tue Jun 10 21:19:57 CST 2014……………..

For this thread task, if we don’t stop the task, it will keep running.

For the above three examples, LZ simply demonstrates the scheduleAtFixedRate method. There is no example of the scheduleAtFixedRate method, which is the same as the schedule method!

4. Analyze schedule and scheduleAtFixedRate

1, Schedule (TimerTask task, Date time), schedule(TimerTask task, long delay)

For both methods, if scheduledExecutionTime<= systemCurrentTime is specified, the task will be executed immediately. The scheduledExecutionTime does not change due to excessive execution of a task.

Schedule (TimerTask task, Date firstTime, long period), schedule(TimerTask task, long delay, long period)

These two methods are slightly different from the above two methods. The Timer task mentioned above will be delayed due to the long execution time of the previous task. In the two methods, the scheduled time of each executed task changes with the actual time of the previous task, that is, scheduledExecutionTime(N +1)=realExecutionTime(n)+periodTime. If systemCurrentTime>= scheduledExecutionTime(n+1), the NTH +1 task will not be executed. He waits for the NTH task to complete before executing it, Therefore, scheduledExecutionTime(N +2) = realExecutionTime(N +1)+periodTime will change due to N +2 executions. Therefore, these two methods pay more attention to the stability of the preservation interval.

3, scheduleAtFixedRate(TimerTask task, Date firstTime, long period), scheduleAtFixedRate(TimerTask task, long delay), long period)

As mentioned above, scheduleAtFixedRate is different from schedule method. Schedule method focuses on the stability of interval time, while scheduleAtFixedRate method focuses on the stability of execution frequency. Why? Here’s why. In the schedule method, subsequent scheduled tasks will be delayed due to the delay of the previous task, but the scheduleAtFixedRate method does not. If the NTH task takes too long and systemCurrentTime>= scheduledExecutionTime(n+1), then no wait is done and the NTH +1 task is executed immediately. Therefore, scheduleAtFixedRate is calculated using scheduledExecutionTime(n)=firstExecuteTime + N *periodTime, which remains the same forever. So scheduleAtFixedRate focuses more on keeping the execution frequency stable.

3. Defects of Timer

1. Defects of Timer

A Timer can be timed (a task is executed at a specified time), delayed (a task is executed at a 5 second delay), and periodically executed (a task is executed every 1 second). However, timers have some drawbacks. Firstly, Timer supports scheduling based on absolute time rather than relative time, so it is very sensitive to changes in system time. Second, the Timer thread will not catch exceptions. If the TimerTask throws an unchecked exception, the Timer thread will terminate. Meanwhile, the Timer will not resume the execution of the thread, and it will mistakenly believe that the whole Timer thread will cancel. At the same time, timerTasks that have been scheduled and have not yet been executed will not be executed, and new tasks cannot be scheduled. So if TimerTask throws an unchecked exception, the Timer will have unexpected behavior.

(1) Defect of Timer management time delay

In the previous Timer, only one thread task will be created when the timed task is executed. If there are multiple threads, some defects will occur if the execution time of one thread is too long and exceeds the interval time of two tasks due to some reasons:

public class TimerTest04 { private Timer timer; public long start; </span><span style="color: #0000ff">public</span><span style="color: #000000"> TimerTest04(){ </span><span style="color: #0000ff">this</span>.timer = <span style="color: #0000ff">new</span><span style="color: #000000"> Timer(); start </span>=<span style="color: #000000"> System.currentTimeMillis(); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerOne(){ timer.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTask() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; timerOne invoked ,the time:&quot; + (System.currentTimeMillis() -<span style="color: #000000"> start)); </span><span style="color: #0000ff">try</span><span style="color: #000000"> { Thread.sleep(</span>4000); <span style="color: #008000">//</span><span style="color: #008000"> #0000ff">catch</span><span style="color: #000000"> (InterruptedException e) { e.printStackTrace(); } } }, </span>1000<span style="color: #000000">); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerTwo(){ timer.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTask() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; timerOne invoked ,the time:&quot; + (System.currentTimeMillis() -<span style="color: #000000"> start)); } }, </span>3000<span style="color: #000000">); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span> main(String[] args) <span style="color: #0000ff">throws</span><span style="color: #000000"> Exception { TimerTest04 test </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> TimerTest04(); test.timerOne(); test.timerTwo(); }}Copy the code

According to our normal thinking, timerTwo should be executed after 3S, and the result should be:

timerOne invoked ,the time:1001 timerOne invoked ,the time:3001

However, contrary to what we want, timerOne sleeps for 4S due to sleep(4000), and the Timer is a thread inside, so the time required by timeOne exceeds the interval time, and the result is:

timerOne invoked ,the time:1000 timerOne invoked ,the time:5000

(2) Timer throws an exception defect

If the TimerTask throws a RuntimeException, the Timer terminates all tasks. As follows:

public class TimerTest04 { private Timer timer; </span><span style="color: #0000ff">public</span><span style="color: #000000"> TimerTest04(){ </span><span style="color: #0000ff">this</span>.timer = <span style="color: #0000ff">new</span><span style="color: #000000"> Timer(); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerOne(){ timer.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTask() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span><span style="color: #000000"> RuntimeException(); } }, </span>1000<span style="color: #000000">); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerTwo(){ timer.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> TimerTask() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; Will I do it? &quot; <span style="color: #000000">); } }, </span>1000<span style="color: #000000">); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { TimerTest04 test </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> TimerTest04(); test.timerOne(); test.timerTwo(); }}Copy the code

Result: timerOne throws an exception, causing the timerTwo task to terminate.

java.lang.RuntimeException

> at com.chenssy.timer.TimerTest04$1.run(TimerTest04.java:25)
> at java.util.TimerThread.mainLoop(Timer.java:555)
> at java.util.TimerThread.run(Timer.java:505)
Copy the code

For the defect of the Timer, we can consider ScheduledThreadPoolExecutor instead. The Timer is based on the absolute time, the system time is sensitive, ScheduledThreadPoolExecutor is based on the relative time; The Timer is within a single thread, and internal is a thread pool ScheduledThreadPoolExecutor, so you can support multiple tasks concurrently.

2. Replace the Timer with ScheduledExecutorService

(1) To solve problem 1:

public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">long</span><span style="color: #000000"> start; ScheduledExecutorTest(){ </span><span style="color: #0000ff">this</span>.scheduExec = Executors.newScheduledThreadPool(2<span style="color: #000000">); </span><span style="color: #0000ff">this</span>.start =<span style="color: #000000"> System.currentTimeMillis(); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerOne(){ scheduExec.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> Runnable() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; timerOne,the time:&quot; + (System.currentTimeMillis() -<span style="color: #000000"> start)); </span><span style="color: #0000ff">try</span><span style="color: #000000"> { Thread.sleep(</span>4000<span style="color: #000000">); } </span><span style="color: #0000ff">catch</span><span style="color: #000000"> (InterruptedException e) { e.printStackTrace(); } } },</span>1000<span style="color: #000000">,TimeUnit.MILLISECONDS); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerTwo(){ scheduExec.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> Runnable() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; timerTwo,the time:&quot; + (System.currentTimeMillis() -<span style="color: #000000"> start)); } },</span>2000<span style="color: #000000">,TimeUnit.MILLISECONDS); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { ScheduledExecutorTest test </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); }}Copy the code

Running results:

timerOne,the time:1003 timerTwo,the time:2005

(2) Solve problem two

public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">long</span><span style="color: #000000"> start; ScheduledExecutorTest(){ </span><span style="color: #0000ff">this</span>.scheduExec = Executors.newScheduledThreadPool(2<span style="color: #000000">); </span><span style="color: #0000ff">this</span>.start =<span style="color: #000000"> System.currentTimeMillis(); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerOne(){ scheduExec.schedule(</span><span style="color: #0000ff">new</span><span style="color: #000000"> Runnable() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { </span><span style="color: #0000ff">throw</span> <span style="color: #0000ff">new</span><span style="color: #000000"> RuntimeException(); } },</span>1000<span style="color: #000000">,TimeUnit.MILLISECONDS); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> timerTwo(){ scheduExec.scheduleAtFixedRate(</span><span style="color: #0000ff">new</span><span style="color: #000000"> Runnable() { </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span><span style="color: #000000"> run() { System.out.println(</span>&quot; timerTwo invoked ..... &quot; <span style="color: #000000">); 2000500}}, < / span > < span style = "color: # 000000" >, TimeUnit. MILLISECONDS); } </span><span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">void</span><span style="color: #000000"> main(String[] args) { ScheduledExecutorTest test </span>= <span style="color: #0000ff">new</span><span style="color: #000000"> ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); }}Copy the code

Running results:

timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. timerTwo invoked ….. .

Four,

I believe you already know how to use Java to achieve the timing effect. Point attention, don’t get lost, pay attention to programmer Zeng Zeng, share different Java knowledge every day. For more Java basics, I put together a GitHub repository of my own:Java little White training manual, you can check it yourself if you need to