The use of timed task @Scheduled in SpringBoot

1. Introduction to @Scheduled annotation

When you need to use scheduled tasks in spring boot projects, you can use the @Scheduled annotation, which is only applicable in a JVM process. If the server is clustered, it is recommended to use a task scheduling platform. In this way, the task scheduling platform will select one of the multiple servers to execute the scheduled task. This annotation is located spring-context.jarin the package

 2. @Scheduled related attribute description

Attributes illustrate
cron():String Create a timed task using a Cron expression, the value can be a string or an expression defined in the acquisition configuration “0 * * * * MON-FRI”file${...}
zone():String Specify the time zone of cron, the default is an empty string, indicating the local time zone
fixedDelay():long The time interval between task execution, indicating the time between the completion of the first task and the start of the second task, unit: milliseconds
fixedRate():long How often to execute the task, the time between the start of the first task and the start of the second task, unit: milliseconds
initialDelay():long Indicates the first execution fixedDelayand fixedRatewaiting time, unit: milliseconds

3. @Scheduled is simple to use

(1) First of all, you need to know that @Scheduled annotation needs to add @EnableScheduling annotation to the system startup class or configuration class to take effect. Here, add @EnableScheduling annotation to the system startup class. As follows:

(2) Create a scheduled task class TestSchedule, annotate it with @Component annotation, and hand it over to the container for management. Define a method taskScheduledOne, and add annotations @Scheduled and cron expressions to the method, as shown in the figure below @Scheduled(cron = "0/10 * * * * ?") indicates that the scheduled task is executed every 10 seconds.

 (3) The execution effect is as follows:

As shown in the printing effect of the above figure, here, a simple timing task has been completed

4. Possible problem 1: The time interval between the execution of two scheduled tasks

The test code looks like this:

@Component
public class TestSchedule {

    /**
     * 每十秒钟执行一次
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void taskScheduledOne() throws InterruptedException {
        Thread t = Thread.currentThread();
        System.out.println("taskScheduledOne "+ DateTimeUtils.dateToString(new Date()) +" ThreadID:"+ t.getId() +" "+t.getName());
        Thread.sleep(5000);
        System.out.println("taskScheduledOne End " + DateTimeUtils.dateToString(new Date()) + " ThreadID:" + t.getId() + " " + t.getName());
    }

    /**
     * 每三秒钟执行一次
     */
    @Scheduled(cron = "0/3 * * * * ?")
    public void taskScheduledTwo() {
        Thread t = Thread.currentThread();
        System.out.println("taskScheduledTwo " + DateTimeUtils.dateToString(new Date()) + " ThreadID:" + t.getId() + " " + t.getName());
    }

}

Run the code, and the initial partial results are printed as shown in the figure: We found that both scheduled task 2 and scheduled task 1 are executed by a thread (thread id is 48), and scheduled task 2 is executed every 3 seconds, but here appears The problem, as shown by the arrow in the figure below, the scheduled task 2 is executed at "2023/06/08 20:24:39", and the next execution time should be "2023/06/08 20:24: 42 ”, but the result shows that the time is 2023/06/08 20:24:45, indicating that there is a problem here.

Explanation of the problem: Because the scheduled tasks marked by @EnableScheduling and @Scheduled in Spring are executed by single thread by default, so scheduled task 2 is executed at arrow A, and scheduled task 1 starts to execute. Both scheduled task 1 and scheduled task 2 are the same thread Executed, the timing task 1 here takes about 5s to execute, which has exceeded the 3s execution cycle of timing task 2, causing timing task 2 to be blocked. So when the scheduled task 2 prints again, it will appear at the arrow B, and the time difference has exceeded 3s.

 5. Possible problem two: use @Async and @EnableAsync to execute tasks asynchronously

 Spring's scheduled task package provides @EnableAsync and @Async annotations for multi-threaded asynchronous execution of tasks.

Add the @EnableAsync annotation to the startup class, and mark the @Async annotation on the TestSchedule class, indicating that all methods marked with @Scheduled in this class use asynchronous processing.

 

 Execute the previous code again to see the effect:

The time interval of scheduled task 2 is 3s, and the time interval of scheduled task 1 is also 10s, and it is not a single-threaded operation.

 This seems to solve the first problem above, but in fact it may introduce the second problem, that is, the execution time of the scheduled task is too long, exceeding the execution period of the scheduled task. Modify the above code and change the sleeping time of the scheduled task 1 thread from 5s to 11s. Execute the code again:

Thread.sleep(5000);
// 改为
Thread.sleep(11000);

The execution effect is as follows: Scheduled task 2 is executed normally. However, there is thread cross-execution in the execution of timed task 1.

Reason explanation: The execution time of the scheduled task 1 exceeds the execution cycle of the scheduled task. When a thread executes the scheduled task 1, it is not over yet, and the next thread starts to execute the scheduled task 1 again. This is to use @EnableAsync and @Async Problems that may arise when executing timed tasks asynchronously.

 

 6. Solutions to Problem 1 and Problem 2

(1) Remove the annotations of the following annotations

 

 (2) Create a task configuration class ScheduleConfig to implement the configureTasks method of the SchedulingConfigurer interface, and use the parameter taskRegistrar to create a thread pool for task scheduling;

@Configuration
@EnableScheduling
public class ScheduleConfig implements SchedulingConfigurer {

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.setScheduler(taskExecutor());
    }

    @Bean(destroyMethod = "shutdown")
    public Executor taskExecutor() {
        return Executors.newScheduledThreadPool(10);
    }
    
}

The running results are shown in the figure below: scheduled task 2 is executed normally, and scheduled task 1 is also executed normally, and there will be no cross phenomenon. The second execution time of scheduled task 1 will wait for the next task scheduling time point after the first execution is completed. It will only be executed at the beginning.

 

 7. Summary

In SpringBoot, @EnableScheduling and @Scheduled annotations can be used to implement scheduled task scheduling, but note that all tasks are scheduled by a single thread by default, and there may be blocking between tasks. You can use @EnableAsync and @Async annotations to implement asynchronous multi-threaded task scheduling , but it should be noted that if the task execution time is greater than the task scheduling cycle time, the same task may be cross-executed. The above 6 can solve related problems.

Guess you like

Origin blog.csdn.net/weixin_42218169/article/details/131113762