background
During project development, we often need to perform periodic tasks. It can help us achieve it well through timing tasks.
Let’s compare several commonly used timed task frameworks:
As can be seen from the above table, the Spring Schedule framework has complete functions and is simple and easy to use. Spring Schedule is fully qualified for small and medium-sized projects.
1. Springboot integration schedule
1.1 Adding maven dependency package
Since Spring Schedule is included in the spring-boot-starter basic module, no additional dependencies are required.
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency></dependencies>
1.2 Start class, add startup annotation
Adding the @EnableScheduling annotation to the springboot entry or configuration class can enable timing tasks.
@EnableScheduling@SpringBootApplicationpublic class ScheduleApplication {public static void main(String[] args) {SpringApplication.run(ScheduleApplication.class, args);}}1.3. Add timed tasks
We will give examples of the three task schedulers of Spring Schedule.
1.3.1 Cron expressions
Similar to the Cron expression time definition rules under Linux. A Cron expression consists of 6 or 7 spaces separated by time fields, as shown in the figure below:
Common expressions:
Take a chestnut:
Add a work() method, which is executed every 10 seconds.
Note: When the execution time of the method exceeds the task scheduling frequency, the scheduler will execute in the next cycle.
For example: Assuming that the work() method starts to be executed at the 0th second and the method is executed for 12 seconds, then the next time the work() method is executed is the 20th second.
@Componentpublic class MyTask {@Scheduled(cron = "0/10 * * * * *")public void work() {// task execution logic}}1.3.2 Fixed interval tasks
The next task execution time is calculated from the end time of the last task execution of the method. And start periodic execution of tasks with this rule.
Take a chestnut:
Add a work() method and execute it every 10 seconds.
For example: Suppose the work() method starts to be executed at the 0th second and the method is executed for 12 seconds, then the next time the work() method is executed is the 22nd second.
@Scheduled(fixedDelay = 1000*10)public void work() {// task execution logic}1.3.3 Fixed frequency tasks
Execute tasks at the specified frequency and start periodic execution of scheduling with this rule.
Take a chestnut:
Add a work() method, which is executed every 10 seconds.
Note: When the execution time of the method exceeds the task scheduling frequency, the scheduler will execute the next task immediately after the current method is executed.
For example: Suppose the work() method starts to be executed at the 0th second and the method is executed for 12 seconds, then the next time the work() method is executed is the 12th second.
@Scheduled(fixedRate = 1000*10)public void work() {// task execution logic}2. Configure the TaskScheduler thread pool
In actual projects, our system may define multiple timing tasks. Then multiple timing tasks can be independently performed and in parallel.
By looking at the org.springframework.scheduling.config.ScheduledTaskRegistrar source code, it is found that spring will create a single-threaded pool by default. This can be fatal for our multitasking. When multiple tasks are executed concurrently (or need to be executed at the same time), the task scheduler will experience time drift and the task execution time will be uncertain.
protected void scheduleTasks() {if (this.taskScheduler == null) {this.localExecutor = Executors.newSingleThreadScheduledExecutor(); this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);}//Omit...}2.1 Custom thread pool
Added a configuration class to implement the SchedulingConfigurer interface. Rewrite the configureTasks method and set a custom thread pool through taskRegistrar.
@Configurationpublic class ScheduleConfig implements SchedulingConfigurer {@Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegistrar) {taskRegistrar.setScheduler(taskExecutor());}@Bean(destroyMethod="shutdown")public Executor taskExecutor() {return Executors.newScheduledThreadPool(20);}}3. Problems in practical applications
3.1 Startup and shutdown issues in web applications
We know that beans loaded or initialized through spring will be automatically unloaded (destroyed) when the service is stopped. However, since threads are JVM-level, if the user starts a thread in a web application, the life cycle of this thread will not be consistent with the web application. That is to say, even if the web application is stopped, the thread still does not end (death).
Solution:
1) The current object is initialized through spring
When spring uninstalls (destroys) an instance, the destroy method of the instance will be called. Implemented by implementing the DisposableBean interface overriding destroy method. Actively close the thread in the destroy method.
@Componentpublic class MyTask implements DisposableBean{@Overridepublic void destroy() throws Exception {//Close the thread or thread pool ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler)applicationContext.getBean("scheduler");scheduler.shutdown();}//Omit...}2) The current object is not initialized (managed) through spring
Then we can add a Servlet context listener to actively close the thread when the Servlet service is stopped.
public class MyTaskListenter implements ServletContextListener{@Overridepublic void contextDestroyed(ServletContextEvent arg0) {//Close thread or thread pool}//Omit...}3.2 Distributed deployment issues
In actual projects, our system will usually be deployed in clusters, distributed or disaster recovery. Then the timing tasks may have concurrency problems, that is, the same task is running on multiple servers at the same time.
Solution (distributed lock):
1) Lock through database table
2) Cache middleware
3) Implemented through Zookeeper
Summarize:
Spring schedule provides us with a simple, fast, efficient and stable timing task framework. However, it is necessary to consider the life cycle of threads and distributed deployment issues.
The above is all the content of this article. I hope it will be helpful to everyone's learning and I hope everyone will support Wulin.com more.