If we need to execute some simple timing tasks during our programming process, we do not need to do complex control. We can consider using Timer timing tasks in JDK to achieve it. The following LZ analyzes the java Timer timer based on its principle, example and Timer defect.
1. Introduction
In Java, a complete timing task needs to be completed by the Timer and TimerTask classes. This is how they are defined in the API. Timer: a tool that uses it to arrange tasks that threads perform in background threads later. Tasks can be executed once, or they can be executed repeatedly. Task scheduled by TimerTask: Timer as a task that is executed or repeated. We can understand that Timer is a timer tool used to plan to execute specified tasks in a background thread, and TimerTask an abstract class whose subclass represents a task that can be planned by Timer.
Timer class <br />In the tool class Timer, four constructor methods are provided. Each constructor starts a timer thread. At the same time, the Timer class can ensure that multiple threads can share a single Timer object without external synchronization, so the Timer class is thread-safe. However, since each Timer object corresponds to a single background thread, which is used to execute all timer tasks in sequence, in general, the time spent on execution of our thread task should be very short. However, due to special circumstances, the execution time of a certain timer task is too long, so it will "exclusively" the timer task execution thread, and all subsequent threads must wait for it to be executed, which will delay the execution of subsequent tasks and make these tasks pile up together. We will analyze the specific situation later.
When the program initializes the Timer, the timing task will be executed according to the time we set. Timer provides the schedule method, which has multiple overloads to adapt to different situations, as follows:
schedule(TimerTask task, Date time): Schedule the execution of the specified task at the specified time.
schedule(TimerTask task, Date firstTime, long period): Schedule the specified task to start repeated fixed delay execution at the specified time.
schedule(TimerTask task, long delay): schedules the specified task to be executed after the specified delay.
schedule(TimerTask task, long delay, long period): schedule the specified task to be executed repeatedly fixed delayed after the specified delay.
At the same time, the scheduleAtFixedRate method is also overloaded. The scheduleAtFixedRate method is the same as schedule, but their focus is different, and the difference is analyzed later.
scheduleAtFixedRate(TimerTask task, Date firstTime, long period): Schedule the specified task to be executed repeatedly at a fixed rate at a specified time.
scheduleAtFixedRate(TimerTask task, long delay, long period): Schedule the specified task to start repeated fixed-rate execution after the specified delay.
TimerTask
The TimerTask class is an abstract class arranged by Timer as a task that is executed or repeated. It has an abstract method run() method, which is used to perform the operations to be performed by the corresponding timer task. Therefore, each specific task class must inherit TimerTask and then override the run() method.
In addition, it has two non-abstract methods:
boolean cancel(): Cancel this timer task.
long scheduledExecutionTime(): Returns the scheduled execution time of the most recent actual execution of this task.
2. Examples
2.1. Specify the delay time to execute timing tasks
public class TimerTest01 { Timer timer; public TimerTest01(int time){ timer = new Timer(); timer.schedule(new TimerTaskTest01(), time * 1000); } public static void main(String[] args) { System.out.println("timer begin..."); new TimerTest01(3); } } public class TimerTaskTest01 extends TimerTask{ public void run() { System.out.println("Time's up!!!"); } } Running results:
First print: timer begin...
Print in 3 seconds: Time's up!!!
2.2. Execute timing tasks at specified time
public class TimerTest02 { Timer timer; public TimerTest02(){ Date time = getTime(); System.out.println("Specify time time=" + time); timer = new Timer(); timer.schedule(new TimerTaskTest02(), time); } public Date getTime(){ Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.HOUR_OF_DAY, 11); calendar.set(Calendar.MINUTE, 39); calendar.set(Calendar.SECOND, 00); Date time = calendar.getTime(); return time; } public static void main(String[] args) { new TimerTest02(); } } public class TimerTaskTest02 extends TimerTask{ @Override public void run() { System.out.println("Execute thread tasks at specified time..."); } } When the time reaches 11:39:00, the thread task will be executed, of course, it will be executed even if it is greater than that time! ! The execution result is:
Specified time=Tue Jun 10 11:39:00 CST 2014
Execute thread tasks at specified time...
2.3. After delaying the specified time, the timing task will be executed at the specified interval time.
public class TimerTest03 { Timer timer; public TimerTest03(){ timer = new Timer(); timer.schedule(new TimerTaskTest03(), 1000, 2000); } public static void main(String[] args) { new TimerTest03(); } } public class TimerTaskTest03 extends TimerTask{ @Override public void run() { Date date = new Date(this.scheduledExecutionTime()); System.out.println("The time for executing this thread is: " + date); } } Running results:
The time for executing this thread is: Tue Jun 10 21:19:47 CST 2014
The time for executing this thread is: Tue Jun 10 21:19:49 CST 2014
The time for executing this thread is: Tue Jun 10 21:19:51 CST 2014
The time for executing this thread is: Tue Jun 10 21:19:53 CST 2014
The time for executing this thread is: 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 do not stop the task, it will continue to run.
For the above three examples, LZ just briefly demonstrated it, and did not explain the example of scheduleAtFixedRate method. In fact, this method is the same as schedule method!
2.4. Analyze schedule and scheduleAtFixedRate
1), schedule(TimerTask task, Date time), schedule(TimerTask task, long delay)
For both methods, if the specified scheduledExecutionTime<= systemCurrentTime, the task will be executed immediately. scheduledExecutionTime will not change due to excessive execution of a task.
2) schedule(TimerTask task, Date firstTime, long period), schedule(TimerTask task, long delay, long period)
These two methods are a bit different from the above two. As mentioned earlier, the Timer timer task will be delayed because the previous task is executed for a long time. In these two methods, the scheduled time of each executed task will change with the actual time of the previous task, that is, scheduledExecutionTime(n+1)=realExecutionTime(n)+periodTime. That is to say, if the nth task causes this execution time process due to some situation, and finally systemCurrentTime>= scheduledExecutionTime(n+1), this is the n+1 task and will not be executed because of the time. It will wait for the nth task to be executed before execution, then this will inevitably lead to the n+2 execution implementation scheduledExecutionTime release and change, that is, scheduledExecutionTime(n+2) = realExecutionTime(n+1)+periodTime. Therefore, these two methods pay more attention to the stability of the storage interval time.
3) scheduleAtFixedRate(TimerTask task, Date firstTime, long period), scheduleAtFixedRate(TimerTask task, long delay, long period)
As mentioned earlier, the focus of scheduleAtFixedRate and schedule methods is different. The schedule method focuses on the stability of the saving interval time, while the scheduleAtFixedRate method focuses more on maintaining the stability of the execution frequency. Why do you say so, the reasons are as follows. In the schedule method, the delay of the previous task will cause the delay of the timing task after it, while the scheduleAtFixedRate method will not. If the execution time of the nth task is too long, systemCurrentTime>= scheduledExecutionTime(n+1), there will be no waiting for it to execute the n+1 task immediately. Therefore, the calculation method of the execution time of the scheduleAtFixedRate method is different from schedule, but scheduledExecutionTime(n)=firstExecuteTime +n*periodTime, and the calculation method will remain unchanged forever. Therefore scheduleAtFixedRate focuses more on keeping the execution frequency stable.
3. Timer's defects
3.1. Timer's defects
Timer timer can time (execute tasks at specified time), delay (delay tasks at 5 seconds), and periodically execute tasks (execute tasks at 1 second), but Timer has some shortcomings. First of all, Timer's support for scheduling is based on absolute time, not relative time, so it is very sensitive to changes in system time. Secondly, the Timer thread will not catch exceptions. If the unchecked exception is thrown by TimerTask, it will cause the Timer thread to terminate. At the same time, the Timer will not resume the thread's execution, and it will mistakenly believe that the entire Timer thread will be cancelled. At the same time, TimerTask, which has been scheduled for not yet executed, will no longer be executed, and new tasks cannot be scheduled. Therefore, if TimerTask throws an unchecked exception, Timer will produce unpredictable behavior.
1) Timer management time delay defect <br />The previous Timer will only create one thread task when executing a timed task. If there are multiple threads, if one of the threads causes the thread task execution time to be too long for some reason, and the interval between the two tasks exceeds the time between them, some defects will occur:
public class TimerTest04 { private Timer timer; public long start; public TimerTest04(){ this.timer = new Timer(); start = System.currentTimeMillis(); } public void timerOne(){ timer.schedule(new TimerTask() { public void run() { System.out.println("timerOne invoked ,the time:" + (System.currentTimeMillis() - start)); try { Thread.sleep(4000); //Thread sleeps 3000 } catch (InterruptedException e) { e.printStackTrace(); } } } }, 1000); } public void timerTwo(){ timer.schedule(new TimerTask() { public void run() { System.out.println("timerOne invoked ,the time:" + (System.currentTimeMillis() - start)); } }, 3000); } public static void main(String[] args) throws Exception { TimerTest04 test = new TimerTest04(); test.timerOne(); test.timerTwo(); } } 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
But things went against my expectations. TimerOne sleeps (4000), sleeps 4S, and the timer is inside the Timer, which causes the time required for timeOne to exceed the interval. The result:
timerOne invoked ,the time:1000
timerOne invoked ,the time:5000
2) Timer throws exception defect
If TimerTask throws a RuntimeException, Timer will terminate all tasks. as follows:
public class TimerTest04 { private Timer timer; public TimerTest04(){ this.timer = new Timer(); } public void timerOne(){ timer.schedule(new TimerTask() { public void run() { throw new RuntimeException(); } }, 1000); } public void timerTwo(){ timer.schedule(new TimerTask() { public void run() { System.out.println("Will I execute it??"); } }, 1000); } public static void main(String[] args) { TimerTest04 test = new TimerTest04(); test.timerOne(); test.timerTwo(); } } Running result: timerOne throws an exception, causing the timerTwo task to terminate.
Exception in thread "Timer-0" 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)
For Timer's defects, we can consider ScheduledThreadPoolExecutor as a replacement. Timer is based on absolute time and is more sensitive to system time, while ScheduledThreadPoolExecutor is based on relative time; Timer is a single thread internally, while ScheduledThreadPoolExecutor is a thread pool internally, so it can support concurrent execution of multiple tasks.
3.2. Replace Timer with ScheduledExecutorService
1) Solve the problem one:
public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; public long start; ScheduledExecutorTest(){ this.scheduExec = Executors.newScheduledThreadPool(2); this.start = System.currentTimeMillis(); } public void timerOne(){ scheduExec.schedule(new Runnable() { public void run() { System.out.println("timerOne, the time:" + (System.currentTimeMillis() - start)); try { Thread.sleep(4000); } catch (InterruptedException e) { e.printStackTrace(); } } } },1000,TimeUnit.MILLISECONDS); } public void timerTwo(){ scheduleExec.schedule(new Runnable() { public void run() { System.out.println("timerTwo,the time:" + (System.currentTimeMillis() - start)); } },2000,TimeUnit.MILLISECONDS); } public static void main(String[] args) { ScheduledExecutorTest test = new ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); } } Running results:
timerOne, the time:1003
timerTwo, the time:2005
2) Solve the problem two
public class ScheduledExecutorTest { private ScheduledExecutorService scheduExec; public long start; ScheduledExecutorTest(){ this.scheduExec = Executors.newScheduledThreadPool(2); this.start = System.currentTimeMillis(); } public void timerOne(){ scheduExec.schedule(new Runnable() { public void run() { throw new RuntimeException(); } },1000,TimeUnit.MILLISECONDS); } public void timerTwo(){ scheduleExec.scheduleAtFixedRate(new Runnable() { public void run() { System.out.println("timerTwo invoked ....."); } },2000,500,TimeUnit.MILLISECONDS); } public static void main(String[] args) { ScheduledExecutorTest test = new ScheduledExecutorTest(); test.timerOne(); test.timerTwo(); } } Running results:
timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ... timerTwo invoked ............ timerTwo invoked ...............
The above is the entire content of this article. This is all about Java timing tasks. I hope it will be helpful to your learning.