In development, we often need some periodic operations, such as performing a certain operation every few minutes. At this time, we need to set a timer. The most convenient and efficient way to implement it in Java is to use the java.util.Timer tool class, and then schedule the java.util.TimerTask task.
Timer is a tool that uses it to arrange tasks that will be executed in background threads later. Tasks can be executed once, or they can be executed repeatedly. It is actually a thread that schedules the TimerTasks owned by timed scheduling.
TimerTask is an abstract class whose subclasses are arranged by Timer as tasks that are executed or repeated. In fact, it is a class with a run method, and the code that needs to be executed regularly is placed into the run method body.
Java launched the timer class Timer in jdk1.3, and then DouLea newly developed the ScheduleThreadPoolExecutor that supports multi-threading after jdk1.5. Judging from the performance of the latter, we can consider completely replacing Timer.
Comparison between Timer and ScheduleThreadPoolExecutor:
1. Timer starts with jdk1.3. Its principle is to use a TimerTask array as a queue to add all timing tasks to this queue. Then start a thread. When the queue is empty, the thread will block. When there is data in the queue, the thread will remove a TimerTask to judge
Whether the time is up to date, the task starts running if the run time is less than or equal to the current time. Due to its single thread nature, it brings several problems (detailed code is later):
First, when the tasks we add to the timer are time-consuming, since this timer executes the timer tasks in a single thread sequential manner, it will affect the timely execution of subsequent tasks.
Java code
//Example of the problem: m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000); m_timer.scheduleAtFixedRate(new TaskNormal(), 5000, 3000); Running result: 14:44:29: timer is sleeping 10 seconds 14:44:39: timer is sleeping 14:44:39: timer is sleeping 10 seconds 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: Task Normal executed 14:44:49: timer is sleeping 10 seconds Results analysis: The TaskNormal task cannot be guaranteed to run once every 3 seconds, it can only wait for TaskUseLongTime to run after it is completed.
Second, the thread in Timer will only catch the InterruptedException exception, so if our custom timing task does not catch possible exceptions and cause the exception to be thrown,
//Example 2: m_timer.schedule(new TaskThrowException(), 1000); m_timer.schedule(new TaskNormal(), 2000); Run result: 14:47:37: Throw exception Exception in thread "Timer-0" java.lang.RuntimeException at timer_test.TimerTest$TaskThrowException.run(TimerTest.java:85) at java.util.TimerThread.mainLoop(Timer.java:512) at java.util.TimerThread.run(Timer.java:462) Results analysis: After an exception is thrown by a task, the subsequent TaskNormal task cannot continue to run.
This will cause our Timer thread to stop, so that other subsequent tasks cannot be executed.
Third, it cannot handle multiple timing tasks that occur simultaneously
//Analysis of the three questions: m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 15000); m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 15000); Running result: 14:50:16: timer1 is sleeping 10 seconds 14:50:26: timer2 is sleeping 10 seconds 14:50:36: timer2 is sleeping 10 seconds Result analysis: My startup time is 1 second later, but the startup time between timer1 and timer2 is obviously inconsistentCode example:
package timer_test;import java.text.SimpleDateFormat;import java.util.Date;import java.util.Timer;import java.util.TimerTask;public class TimerTest {private final Timer m_timer = new Timer();public static void main(String[] args) {new TimerTest().test();}public void test() {//A sample of the problem: m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000);m_timer.scheduleAtFixedRate(new TaskNormal(), 5000, 3000);//Example 2: // m_timer.schedule(new TaskThrowException(), 1000); // m_timer.schedule(new TaskNormal(), 2000); //Example 3: // m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000); // m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000);}private class TaskUseLongTime extends TimerTask {private String m_taskName = "timer";public TaskUseLongTime(){}public TaskUseLongTime(String taskName) {m_taskName = taskName;}@Override public void run() {try {System.out.println(getCurrentTime()+": "+m_taskName+" is sleeping 10 seconds");Thread.sleep(10000);}catch (InterruptedException e) {}}}private class TaskNormal extends TimerTask {@Override public void run() {System.out.println(getCurrentTime()+": Task Normal executed");}}private class TaskThrowException extends TimerTask {@Override public void run() {System.out.println(getCurrentTime()+": Throw exception");throw new RuntimeException();}}private String getCurrentTime() {return new SimpleDateFormat("HH:mm:ss").format(new Date());}}2.ScheduleThreadPoolExecutor
ScheduleThreadPoolExecutor started with jdk1.5 and was written by Mr. DouLea. It uses the clever combination of ThreadPoolExecutor and DelayQueue to complete the implementation of multi-threaded timer, solving the above three defects caused by single thread in Timer.
The problem in question 1 is that the subsequent tasks cannot be completed on time because single threads execute sequentially. We see that multi-threading can easily solve this problem. At the same time, we noticed that the execution time of TaskUseLongTime is 10s (please see the subsequent code). We timed the task interval of 5 seconds, but from the result, we found that our task execution interval is 10 seconds, so we can judge that ScheduleThreadPoolExecutor works in a per-thread-per-task mode.
//Problem 1: m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000, TimeUnit.MILLISECONDS); m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS); Running result: 14:54:37: Task Normal executed 14:54:37: timer is sleeping 10 seconds 14:54:42: Task Normal executed 14:54:47: Task Normal executed 14:54:47: Task Normal executed 14:54:47: timer is sleeping 10 seconds 14:54:52: Task Normal executed
In question 2, we found that when the exception is thrown, the execution of the task does not affect the operation of other tasks. At the same time, we found that our exception was not thrown in the run result. This is because the ScheduleThreadPoolExecutor class will return a ScheduledFuture run result after executing the timed task. Whether the result is successful or there are exceptions, it will be saved here.
//Problem 2: m_timer.scheduleAtFixedRate(new TaskThrowException(), 1000, 5000, TimeUnit.MILLISECONDS); m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS); Running result: 14:58:36: Throw exception 14:58:36: Task Normal executed 14:58:41: Task Normal executed 14:58:46: Task Normal executed 14:58:46: Task Normal executed 14:58:46: Task Normal executed 14:58:51: Task Normal executed 14:58:56: Task Normal executed
Question 3 Since it is multi-threaded, we can ensure that our timing tasks can be executed at the same time.
//Problem 3: m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000, TimeUnit.MILLISECONDS); m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000, TimeUnit.MILLISECONDS); Running result: 15:01:12: timer1 is sleeping 10 seconds 15:01:12: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01:22: timer2 is sleeping 10 seconds 15:01: seconds 15:01:22: timer1 is sleeping 10 seconds 15:01:32: timer1 is sleeping 10 seconds 15:01:32: timer2 is sleeping 10 secondsDetailed code:
package timer_test;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.Callable;import java.util.concurrent.ScheduledThreadPoolExecutor;import java.util.concurrent.TimeUnit;public class ScheduleThreadPoolExecutorTest {private final ScheduledThreadPoolExecutor m_timer = new ScheduledThreadPoolExecutor(10);public static void main(String[] args) {ScheduleThreadPoolExecutorTest timerTest = new ScheduleThreadPoolExecutorTest();timerTest.test();try {Thread.sleep(100000);}catch (InterruptedException e) {} finally {timerTest.shutdown();}}public void shutdown() {m_timer.shutdown();}public void test() {// Question 1: // m_timer.scheduleAtFixedRate(new TaskUseLongTime(), 1000, 5000, TimeUnit.MILLISECONDS); // m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS); // Question 2: // m_timer.scheduleAtFixedRate(new TaskThrowException(), 1000, 5000, TimeUnit.MILLISECONDS); // m_timer.scheduleAtFixedRate(new TaskNormal(), 1000, 5000, TimeUnit.MILLISECONDS); //Problem 3: m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer1"), 1000, 5000, TimeUnit.MILLISECONDS);m_timer.scheduleAtFixedRate(new TaskUseLongTime("timer2"), 1000, 5000, TimeUnit.MILLISECONDS);}private class TaskUseLongTime implements Callable<Integer>, Runnable {private String m_taskName = "timer";private TaskUseLongTime(){}private TaskUseLongTime(String taskName) {m_taskName = taskName;}public void run() {try {System.out.println(getCurrentTime()+": "+m_taskName+" is sleeping 10 seconds");Thread.sleep(10000);}catch (InterruptedException e) {}}public Integer call() throws Exception {run();return 0;}}@SuppressWarnings("unused") private class TaskNormal implements Callable<Integer>, Runnable {public Integer call() throws Exception {run();return 0;}public void run() {System.out.println(getCurrentTime()+": Task Normal executed");}}@SuppressWarnings("unused") private class TaskThrowException implements Callable<Integer>, Runnable {public Integer call() throws Exception {System.out.println(getCurrentTime()+": Throw exception");throw new RuntimeException();}public void run() {System.out.println(getCurrentTime()+": Throw exception");throw new RuntimeException();}}private String getCurrentTime() {return new SimpleDateFormat("HH:mm:ss").format(new Date());}}Summarize
The above is all about this article's brief discussion on the development history of Java timers, and I hope it will be helpful to everyone. Interested friends can continue to refer to this site:
Java implements a simple timer code parsing
The principle and implementation of Java multithreaded timer Timer
Code example of how to use java timer timer
If there are any shortcomings, please leave a message to point it out. Thank you friends for your support for this site!