Detailed explanation of SpringBoot timing tasks and Cron expressions

1. Overview of timed tasks Timed tasks are often used in

background project development, and now there are various ways to implement timed tasks. Here are some common implementations of timed tasks:
1. Quartz: Quartz is widely used, it is a powerful scheduler, and of course it is relatively troublesome to use;
2. The Timer in the java.util package can also be used Implement timed tasks but the function is too single so it is rarely used.
3. It is the scheduled task Schedule that comes with Spring that we are going to introduce today. In fact, it can be regarded as a simplified version of the lightweight Quartz, which is relatively convenient to use.
2. Implementing scheduled tasks

1. Create scheduled tasks

import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.scheduling.annotation.Scheduled;import org.springframework.stereotype.Component;/**
* Description: Build and execute timed tasks
* Designer: jack
* Date: 2017/8/10
* Version: 1.0.0
*/@Componentpublic class ScheduledTasks { private Logger logger = LoggerFactory.getLogger(ScheduledTasks.class); private int fixedDelayCount = 1; private int fixedRateCount = 1; private int initialDelayCount = 1; private int cronCount = 1; @Scheduled(fixedDelay = 5000 ) //fixedDelay = 5000 means that after the current method is executed for 5000ms, Spring scheduling will call the method again
public void testFixDelay() {
logger.info("===fixedDelay: The {}th execution method", fixedDelayCount++);
} @ Scheduled(fixedRate = 5000) //fixedRate = 5000 means that after the current method starts to execute 5000ms, Spring scheduling will call the method again
public void testFixedRate() {
logger.info("===fixedRate: execute method for the {}th time", fixedRateCount++);
} @Scheduled(initialDelay = 1000, fixedRate = 5000) //initialDelay = 1000 means delay 1000ms to execute the first task
public void testInitialDelay() {
logger.info("===initialDelay: The {}th execution method", initialDelayCount++);
} @Scheduled(cron = "0 0/1 * * * ?") //cron accepts cron expressions, according to cron expressions Determine timing rules
public void testCron() {
logger.info("===initialDelay: {}th execution method", cronCount++);
}
}
We use @Scheduled to create a scheduled task. This annotation is used to annotate a scheduled task method. By looking at the @Scheduled source code, it can be seen that it supports a variety of parameters:
(1) cron: cron expression, specifying that the task is executed at a specific time;
(2) fixedDelay: Indicates how long after the last task execution is completed, the parameter type is long , unit ms;
(3) fixedDelayString: the same as fixedDelay, except that the parameter type becomes String;
(4) fixedRate: indicates that the task is performed at a certain frequency, the parameter type is long, and the unit is ms;
(5) fixedRateString: the same as fixedRate The meaning is the same, but the parameter type is changed to String;
(6) initialDelay: indicates how long to delay before executing the task for the first time, the parameter type is long, and the unit is ms;
(7) initialDelayString: The meaning of initialDelay is the same, but the parameter type is changed to It is String;
(8) zone: time zone, the default is the current time zone, which is generally not used.
2. To enable scheduled tasks
import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.scheduling.annotation.EnableScheduling;/**
* Description: Startup class
* Designer: jack
* Date : 2017/8/10
* Version: 1.0.0
*/@SpringBootApplication@EnableScheduling public class Application { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Note @EnableScheduling here Annotation, its role is to discover tasks annotated @Scheduled and execute them in the background. Without it, scheduled tasks cannot be executed.
Quoting the original text of the official document:
@EnableScheduling ensures that a background task executor is created. Without it, nothing gets scheduled.
3. Execution result (single thread)
At this point, we have completed a simple timed task model. Next, execute springBoot to observe the execution results.
2017-08-11 12:06:19.738 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks: ===initialDelay: 1st execution method 2017-08-11 12:06:23.739 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks: ===fixedRate: 2nd execution method 2017-08-11 12:06:23.739 INFO 52252 --- [pool-1- thread-1] com.test.ScheduledTasks : ===fixedDelay: 2nd execution method 2017-08-11 12:06:24.738 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks : ===initialDelay: 2nd execution method 2017-08-11 12:06:28.739 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks : ===fixedRate: 3rd execution method 2017-08-11 12:06:28.740 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks: ===fixedDelay: 3rd execution method 2017-08-11 12:06:29.739 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks: ===initialDelay: 3rd execution method 2017-08-11 12:06:33.735 INFO 52252 --- [pool-1- thread-1] com.test.ScheduledTasks : ===fixedRate: 4th execution method 2017-08-11 12:06:33.741 INFO 52252 --- [pool-1-thread-1] com.test.ScheduledTasks: ===fixedDelay: 4th execution method 2017-08-11 12:06:34.738 INFO 52252 --- [pool-1 -thread-1] com.test.ScheduledTasks : ===initialDelay: 4th execution method
From the results input from the console, we can see that all timing tasks are processed in the same thread pool with the same thread, so how do we process each timing task concurrently, please continue to look down.
4. Multi-threaded processing of timed tasks
Seeing the console output results, all timed tasks are processed by one thread. I guess a SingleThreadScheduledExecutor is set in the configuration of timed tasks, so I read the source code, from The ScheduledAnnotationBeanPostProcessor class begins to look all the way. Sure enough, there is another judgment in ScheduleTasks in ScheduledTaskRegistrar (timed task registration class):
if (this.taskScheduler == null) { this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor) ;
}
This means that if the taskScheduler is empty, then a single-threaded thread pool is created for the timed task. There is also a method for setting the taskScheduler in this class:
public void setScheduler(Object scheduler) {
Assert.notNull(scheduler , "Scheduler object must not be null"); if (scheduler instanceof TaskScheduler) { this.taskScheduler = (TaskScheduler) scheduler;
} else if (scheduler instanceof ScheduledExecutorService) { this.taskScheduler = new ConcurrentTaskScheduler(((ScheduledExecutorService) scheduler)); } else {
throw new IllegalArgumentException("Unsupported scheduler type: " + scheduler.getClass()); It's very simple, we only need to explicitly set a ScheduledExecutorService by calling this method to achieve the effect of concurrency. All we have to do is to implement the SchedulingConfigurer interface and rewrite the configureTasks method is OK; import org.springframework.context.annotation.Configuration;import org.springframework.scheduling.annotation.SchedulingConfigurer;import org.springframework.scheduling.config.ScheduledTaskRegistrar ;import java.util.concurrent.Executors;/** * Description: Multi-threaded execution of scheduled tasks * Designer: jack * Date: 2017/8/10 * Version: 1.0.0








*/@Configuration//All timing tasks are placed in a thread pool, and different threads are used when timing tasks are started. public class ScheduleConfig implements SchedulingConfigurer { @Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { //Set a timed task thread pool with a length of 10
taskRegistrar.setScheduler(Executors.newScheduledThreadPool(10));
}
}
Note: At first I tried to use ScheduledAnnotationBeanPostProcessor Make a fuss in the class, because there is a similar method setScheduler() in it, but it fails in the end. I don’t know if the concurrency of timed tasks can be realized through this class. If there is one, please tell everyone the method.
5. Execution results (concurrency)
2017-08-11 12:21:16.000 INFO 52284 --- [pool-1-thread-3] com.test.ScheduledTasks: ===initialDelay: 1st execution method 2017-08-11 12:21:19.998 INFO 52284 --- [pool-1-thread-4] com.test.ScheduledTasks: ===fixedRate: 2nd execution method 2017-08-11 12:21:19.998 INFO 52284 --- [pool-1- thread-1] com.test.ScheduledTasks : ===fixedDelay: 2nd execution method 2017-08-11 12:21:20.999 INFO 52284 --- [pool-1-thread-4] com.test.ScheduledTasks : ===initialDelay: 2nd execution method 2017-08-11 12:21:25.000 INFO 52284 --- [pool-1-thread-2] com.test.ScheduledTasks : ===fixedRate: 3rd execution method 2017-08-11 12:21:25.000 INFO 52284 --- [pool-1-thread-6] com.test.ScheduledTasks: ===fixedDelay: 3rd execution method 2017-08-11 12:21:25.997 INFO 52284 --- [pool-1-thread-3] com.test.ScheduledTasks: ===initialDelay: 3rd execution method 2017-08-11 12:21:30.000 INFO 52284 --- [pool-1- thread-7] com.test.ScheduledTasks : ===fixedRate: 4th execution method 2017-08-11 12:21:30.000 INFO 52284 --- [pool-1-thread-8] com.test.ScheduledTasks: ===fixedDelay: 4th execution method 2017-08-11 12:21:31.000 INFO 52284 --- [pool-1 -thread-7] com.test.ScheduledTasks : ===initialDelay: 4th execution method
It can be seen from the console output that each timed task is being processed by a different thread.
3. Detailed explanation of cron

1. Cron expression definition
Cron expression is a string, which is composed of 6 or 7 fields separated by spaces, each field corresponds to a meaning (second, minute, month, day, month, week, year) where year is an optional field.
However, tap the blackboard here, the schedule value of spring supports expressions of 6 fields, that is, the year cannot be set, and an error will be reported if there are more than six. The source code is as follows:
/**
* Parse the given pattern expression.
*/
private void parse(String expression) throws IllegalArgumentException {
String[] fields = StringUtils.tokenizeToStringArray(expression, " "); if (!areValidCronFields(fields)) { throw new IllegalArgumentException(String.format( "Cron expression must consist of 6 fields (found %d in \"%s\")", fields.length, expression));
}
setNumberHits(this.seconds, fields[0], 0 , 60);
setNumberHits(this.minutes, fields[1], 0, 60);
setNumberHits(this.hours, fields[2], 0, 24);
setDaysOfMonth(this.daysOfMonth, fields[3]);
setMonths(this.months, fields[4]);
setDays(this.daysOfWeek, replaceOrdinals(fields[ 5], "SUN,MON,TUE,WED,THU,FRI,SAT"), ; if (this.daysOfWeek.get(7)) { // Sunday can be represented as 0 or 7
this.daysOfWeek.set(0 ); this.daysOfWeek.clear(7);
}
} private static boolean areValidCronFields(String[] fields) { return (fields != null && fields.length == 6);
}
2. Types of characters that can appear in each field and the meaning of each character
(1) The type of characters supported by each field
Second : four characters ", - * /" can appear, and the valid range is an integer of 0-59
Minute: four characters ", - * /" can appear, When the valid range is an integer
of : four characters ", - * /" can appear, and the valid range is an integer of 0-23
Day of the month: ", - * / ? LW C" can appear Eight characters, valid integers in the range 0-31
Month: four characters of ", - * /" can appear, and the valid range is an integer of 1-12 or JAN-DEc
Week: four characters of ", - * / ? LC #" can appear, and the valid range is 1-7. Integer or SUN-SAT two ranges. 1 means Sunday, 2 means Monday, and so on
(2) Meaning of special characters
* : Indicates any value that matches the field, for example, in seconds *, it means that an event will be triggered every second. ;
? : Can only be used in the fields of the day and week of the month. Indicates that no value is specified. When one of the two sub-expressions is assigned a value, in order to avoid conflicts, the value of the other sub-expression needs to be set to "?";
- : Indicates the range, for example, use 5- 20, which means triggering every minute from 5 minutes to 20 minutes
/ : means triggering at the start time, and then triggering every fixed time, for example, using 5/20 in the sub-domain means 5 minutes, 25 minutes, 45 minutes , which are triggered once.
, : indicate enumeration values ​​are listed. For example: using 5, 20 in the subfield, it means triggering once at 5 and 20 minutes.
L : Indicates the last, which can only appear in the field of the day of the week and the month of the month. If you use 1L in the field of the week, it means that it will be triggered on the last Sunday.
W : Indicates a valid working day (Monday to Friday), which can only appear in the field of the day of the month. The system will trigger the event on the nearest valid working day from the specified date. Note that the most recent search for W will not span the month
LW : these two characters can be used together to indicate the last working day of a month, that is, the last Friday.
# : Used to determine the day of the week in each month. It can only appear in the day of the month field. For example, in 1#3, it means the third Sunday of a month.
(3) Expression examples
Refer to the official spring notes:
* <p>Example patterns:
* <ul>
* <li>"0 0 * * * *" = the top of every hour of every day.</li>
* <li>"*/10 * * * * *" = every ten seconds.</li>
* <li>"0 0 8-10 * * *" = 8, 9 and 10 o'clock of every day.</li>
* <li>"0 0/30 8-10 * * *" = 8:00, 8:30, 9:00, 9:30 and 10 o'clock every day.</li>
* <li>"0 0 9-17 * * MON-FRI" = on the hour nine-to-five weekdays</li>
* <li>"0 0 0 25 12 ?" = every Christmas Day at midnight</li>
"0 0 * * * *" 表示每小时0分0秒执行一次
" */10 * * * * *" 表示每10秒执行一次
"0 0 8-10 * * *" 表示每天8,9,10点执行
"0 0/30 8-10 * * *"It means that "0 0 0 25 12 ?" Indicates that every Christmas (December 25th) 0:0:00 is executed at 0:00:00
"0 0 9-17 * * MON-FRI" is

Attached source code address: http://git.oschina.net/jack90john/spring-boot-timmer

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326198003&siteId=291194637