Preface
As the name implies, a timer triggers an event on time, separated from three factors: timing, triggering, an event. This paper will also introduce five common timers based on this.
This article only makes an example based on SpringBoot, the rest of the versions please consult the materials yourself, much the same.
1. Introduction
1.1. objective
The purpose of the timer is to actively trigger an event by the program itself at a certain point in time without any external effort to open or start it, in order to save labor and manage it uniformly.
1.2. Sample Scenario
- Management system that backs up data from the previous day at 12 o'clock a day and generates historical data statistics
- Housekeeping system, counts all the unreturned people at 10 o'clock a day and gives them to managers on their own initiative
- Hardware devices, need to check every 2 minutes whether the device is connected properly, device abnormalities need to update the status to the management side, if necessary, notify relevant personnel
- Library borrowing management system that checks for books that are about to time out and have been returned overtime at 12 o'clock a day and notifies people by text message or other means
- Mobile download management system, refreshes the download progress every 0.5s after opening the download, and informs users when the download is complete or when it takes a long time to carton
- An order management system in which users pay within half an hour after placing an order, successful payment generates an order result, and unpaid overtime automatically cancels the order
Do you think it's common?
1.3. Common implementation scenarios
- @Scheduled Note: Note-based
- Timer(). Schdule creation task: based on encapsulation class Timer
- Threads: use threads to perform tasks directly, which can be used with threads, thread pools, ScheduleTask s, and so on
- Quartz configuration timer: spring-based quartz framework
In this paper, only the first three are briefly described. They are easy to understand and quartz will be separated and sorted out.
2.@Scheduled comment
2.1. Introduction:
Use annotations to mark methods that need to be executed regularly and set the execution time so that they can execute the specified method at the specified time
2.2. Steps:
- Tag the target method with the comment @Scheduled parameter Execution Time
- Use the comment @EnableScheduling to mark the class where the target method is located, or directly mark the project startup class
2.3. Notes:
- Annotation @Scheduled is a method annotation that marks when a method is executed at a fixed time
- Need to be used with another comment @EnableScheduling, which marks a class, opens a timer task, usually the class where the timer is located, or is set directly on the project startup class
2.4.@Scheduled parameter:
-
@Scheduled(fixedDelay = 5000): Wait 5 seconds for the method to execute again after execution is complete
-
@Scheduled(fixedRate = 5000): Method executes every 5 seconds
-
@Scheduled(initialDelay=1000, fixedRate=5000): executes the first time after a delay of one second, then every five seconds
-
fixedDelayString, fixedRateString, initialDelayString: works with appeal all the time, but the parameter is of string type, so you can use placeholders, such as
@Scheduled(fixedDelayString = "${time.fixedDelay}")
-
@Scheduled (cron = "0,30,8?*?"): The method is executed at 8:30 seconds a day and the parameters are of string type. Placeholders can also be used in the same way. Please look up the cron expression separately. This article is recommended: https://www.jianshu.com/p/1defb0f22ed1
2.5. Example
Example 1: Execute every 3 seconds
@Component @EnableScheduling public class ScheduleTest { private int count = 0; /** * Execute every 3 seconds */ @Scheduled(cron = "*/3 * * * * ?") public void test1() { System.out.println(count + ": " + (new Date()).toString()); count++; } }
Example 2: First wait for 10 seconds, then every 3 seconds
@Component @EnableScheduling public class ScheduleTest { private int count = 0; /** * Wait for 10 seconds for the first time, then execute every 3 seconds */ @Scheduled(initialDelay = 10000, fixedRate = 3000) public void test1() { System.out.println(count + ": " + (new Date()).toString()); count++; } }
2.6. Summary
- Advantage: Simple and convenient, with just two lines of commentary to complete the timed effect
- Disadvantage: All parameters and methods of execution must be written into code ahead of time, with very low scalability
3.Timer(). Schdule Create Task
3.1. Sample
It's very simple to use, so here's an example to show how to use it
The code is as follows
package com.yezi_tool.demo_basic.test; import org.springframework.stereotype.Component; import java.util.Date; import java.util.Timer; import java.util.TimerTask; @Component public class TimerTest { private Integer count = 0; public TimerTest() { testTimer(); } public void testTimer() { new Timer().schedule(new TimerTask() { @Override public void run() { try { //do Something System.out.println(new Date().toString() + ": " + count); count++; } catch (Exception e) { e.printStackTrace(); } } }, 0, 1000); } }
results of enforcement
You can see count s are printed every 1s and increase by 1
3.2. introduce
The core includes Timer and TimerTask, which are both jkd's own tool classes, with 721 lines of code and 162 lines of code (including comments), respectively. If you are interested, you can look directly at the source code
3.2.1.TimerTask
TimerTask is actually just a Runnable. It inherits Runnable and adds several custom parameters and methods. Nothing to mention, it's interesting to see the source code
3.2.2.Timer
Timer literally means timer, which provides jkd's own tool class with functions to perform tasks on time
There are actually three classes:
-
Timer: The main timer class, which manages all the timer tasks. Each Timer has a private TaskQueue and TimerThread.
-
TaskQueue: Task queue, Timer production task, and then pushed to TaskQueue for processing, which removes the processed task
TaskQueue essentially has only one 128-length array to store TimerTask, an int variable size to represent the queue length, and a review of additions and deletions to both data
-
TimerThread: A timer thread that shares data in TaskQueue and consumes tasks in TaskQueue
TimerThread is essentially a Thread thread that constantly listens to TaskQueue and executes the first if there are tasks in the queue and deletes them (delete and execute first).
Process analysis
- Timer production tasks (which are actually received from outside) push the tasks into TaskQueue and wake up the TaskQueue thread (queue.notify())
- TimerThread listens on TaskQueue, executes it if there are tasks in it, removes it from the queue, and leaves the queue waiting if there are no tasks (queue.wait())
In this way, it's not the typical==producer/consumer mode==, timer is responsible for production (actually acceptance), TimerThread is responsible for consumption, and TaskQueue is used as a transit warehouse
Construction method
The name of the timer thread is set and started when it is constructed
The complete format is as follows, with two parameters available by default
public Timer(String name, boolean isDaemon)
- 1
- Name: The name of the thread used to distinguish between different threads. By default, "Timer-" + serialNumber() is used to generate a unique thread name
- isDaemon: Is it a daemon thread, defaults to no by default, what's different? I'll organize my notes if I have the chance
Core approach
Core methods include adding tasks, canceling tasks, and purifying
-
There are six common methods for adding tasks (the same private method is actually used last)
- schedule(TimerTask task, long delay): Specifies the task to execute after a delay of milliseconds
- schedule(TimerTask task, Date time): Specifies the task to be executed once at the time point
- schedule(TimerTask task, long delay, long period): Specifies the task, delays the first execution after milliseconds, and then executes every period millisecond after that
- Schedule (TimerTask task, Date first time, long period): Specifies the task to be executed for the first time at the first time, and then every periodms
- scheduleAtFixedRate(TimerTask task, long delay, long period): works in accordance with schedule
- ScheduleAtFixedRate (TimerTask task, Date first Time, long period): works in accordance with schedule
In fact, sched(TimerTask task, long time, long period) is used at the end, that is, to specify the task to be executed for the first time in time and then every periodms
Schdule uses system time to calculate the next time, System.currentTimeMillis()+period
SchduleAtFixedRate uses this estimated time to calculate the next time, time + period
For time-consuming tasks, there is a big difference between the two. Select tasks on demand, no difference between instantaneous tasks
-
Cancel Task Method: cancel(), empties the task queue, blocks threads, and no longer accepts tasks (accepts errors), and does not destroy its own instance and its internal threads
-
Purification method: purge(), which removes all canceled tasks from the queue, heaps the remaining tasks, and returns the number of removed tasks
supplement
-
How to ensure that the first task is executed earliest
Task queues perform heap sorting corrections each time tasks are added or deleted, and purification reorders the remaining tasks
-
How threads handle cancel
The timer thread was blocked and not destroyed. It will not execute the next time it executes the current task, but the ** thread was not destroyed **
So try not to create too many timer objects, which can increase the server load
3.3. Use steps
-
Initialize Timer
Timer timer=new Timer();
-
Initialize task
private class MyTask extends TimerTask { @Override public void run() { try { //do Something System.out.println(new Date().toString() + ": " + count); count++; } catch (Exception e) { e.printStackTrace(); } } } }
MyTask myTask=new MyTask();
-
Add Task
timer.schedule(myTask, 5000, 3000);
Full code:
package com.yezi_tool.demo_basic.test; import org.springframework.stereotype.Component; import java.util.Date; import java.util.Timer; import java.util.TimerTask; @Component public class TimerTest { private Integer count = 0; public TimerTest() { testTimer2(); } public void testTimer2() { Timer timer = new Timer(); MyTask myTask = new MyTask(); timer.schedule(myTask, 0, 1000); } private class MyTask extends TimerTask { @Override public void run() { try { //do Something System.out.println(new Date().toString() + ": " + count); count++; } catch (Exception e) { e.printStackTrace(); } } } }
Of course, it can be abbreviated as the writing in the sample, more concise, please modify it to suit your needs
4. Threads
Threads should be the most common implementation. Creating a thread to perform a task can be as follows
4.1. Use thread + runnable
package com.yezi_tool.demo_basic.test; import org.springframework.stereotype.Component; import java.util.Date; @Component public class ThreadTest { private Integer count = 0; public ThreadTest() { test1(); } public void test1() { new Thread(() -> { while (count < 10) { System.out.println(new Date().toString() + ": " + count); count++; try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }).start(); } }
4.2. Use thread pool + runnable
package com.yezi_tool.demo_basic.test; import org.springframework.stereotype.Component; import java.util.Date; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @Component public class ThreadTest { private static final ExecutorService threadPool = Executors.newFixedThreadPool(5);// Thread Pool private Integer count = 0; public ThreadTest() { test2(); } public void test2() { threadPool.execute(() -> { while (count < 10) { System.out.println(new Date().toString() + ": " + count); count++; try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } }); } }
4.3. Using ScheduledTask + runnable
ScheduledTask has 11 ways to add tasks, check the file TaskScheduler directly for details. Java, here are some common examples
-
Set trigger frequency to 3000ms
package com.yezi_tool.demo_basic.test; import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Component; import java.util.Date; @Component public class ThreadTest { private Integer count = 0; private final TaskScheduler taskScheduler; public ThreadTest(TaskScheduler taskScheduler) { this.taskScheduler = taskScheduler; test3(); } public void test3() { taskScheduler.scheduleAtFixedRate(() -> { System.out.println(new Date().toString() + ": " + count); count++; }, 3000); } }
-
Set the trigger time to 1 AM each day
package com.yezi_tool.demo_basic.test; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Component; import java.util.Date; @Component public class ThreadTest { private Integer count = 0; private final TaskScheduler taskScheduler; public ThreadTest(TaskScheduler taskScheduler) { this.taskScheduler = taskScheduler; test4(); } public void test4() { taskScheduler.schedule(() -> { System.out.println(new Date().toString() + ": " + count); count++; }, new CronTrigger("0 0 1 * * ?")); } }
5.quartz
I've compiled a quartz note for interesting people to read my last blog
Writing is not perfect and should be corrected later
6. Summary
- @schedule is quick and easy to use, but has limited functionality and is extremely scalable for simple scenarios that do not require unified management
- Timer can manage timed tasks uniformly, but as a tool class, Timer has less functionality, but it can also be used in many scenarios
- Threads are also convenient to use, flexible and support all types of trigger time, but after all, there is no dedicated framework, not very full functionality, suitable for scenes with higher freedom requirements
- Quatz is a full-featured and powerful timer project. Currently, most projects only use a small part of its functionality, which is suitable for more demanding scenarios
7.demo address
https://gitee.com/echo_ye/demo_basic/tree/scheduleDemo
Different timer enabling methods in README. There are 6 ways to view it in MD. Please contact me if there are any errors
Only some of the functions have been implemented as an example, please expand as needed. If you have questions or suggestions, please contact me ~
Conclusion:
In fact, in addition to @schedule, all other can be customized to unify management and dynamically modify, not to mention here
Quatz has sorted out all the interesting timers besides static and dynamic timers.