Spring boot uses spring's built-in scheduled tasks

Original link

https://cloud.tencent.com/developer/article/1582434

1. Preface

We often use timed tasks in daily project development. For example, make statistics and settlement in the early morning, start planning activities, automatically change the unpaid orders that exceed 24 hours to cancelled status, and automatically change the orders that have not been signed by customers for more than 14 days to signed status, etc. Let's take a look at how Spring's built-in boot tasks are used today.

2. Four ways to implement timed tasks in spring

2.1 Spring Task

Spring Task: Spring3. The task built after 0 can be regarded as a lightweight Quartz, and it is much simpler to use than Quartz.

2.1.1 @ enablesscheduling enable scheduled tasks

By default, Spring Boot uses the scheduled task tool Spring Task provided under the spring context module without any third-party dependency. We only need to use the @ enablesscheduling annotation to enable the related scheduled task functions. For example:

@SpringBootApplication
@EnableScheduling
public class SpringbootScheduleApplication {
    public static void main(String[] args) {
	SpringApplication.run(SpringbootScheduleApplication.class, args);
    }
}

Then we can implement custom scheduled tasks by annotation.

2.1.2 @Scheduled implements scheduled tasks

@Component
public class Task {

    @Scheduled(fixedDelay = 1000)
    public void task() {
        System.out.println("Thread Name : "
                + Thread.currentThread().getName() + "  i am a task : date ->  "
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }
}

result:

Note: the @ Scheduled annotation must state the execution strategy of Scheduled tasks. Choose one of cron, fixedDelay and fixedRate.

2.1.3 method introduction in @ scheduled

2.1.3.1 cron

2.1.3.2 fixedDelay

fixedDelay: its interval is timed according to the end of the last task. Just keep an eye on the end of the last execution. It has nothing to do with the execution time of task logic. The interval between two rounds is fixed.

2.1.3.3 fixedRate

Fixed rate: This is relatively difficult to understand. Ideally, the time interval between the next start and the last start is certain. However, by default, Spring Boot scheduled tasks are executed in a single thread. After the task of the next round meets the time policy, the task will be added to the queue, that is, when this task starts to execute, the time of the next task has been determined. Due to the "timeout" execution of this task, the waiting time of the next task will be compressed or even blocked. Just draw a picture.

2.1.3.4 initialDelay

initialDelay: initialization delay time, that is, the time when the execution is delayed for the first time. This parameter is not valid for cron attribute and can only be used with fixedDelay or fixedRate. For example, @ Scheduled(initialDelay=5000,fixedDelay = 1000) indicates that the execution of the first task is delayed by 5000 milliseconds, and the next task is executed after 1000 milliseconds after the end of the previous task.

2.1.4 detailed explanation of cron expression

Original link: https://cloud.tencent.com/developer/article/1674682

2.1.5 disadvantages of spring task

Spring's scheduled tasks are executed by single thread by default. In the case of multitasking, the use of multithreading will affect the timing strategy

@Component
public class TaskService {
    /**
     * One second after the last task, execute the next task, which takes 5 seconds
     *
     * @throws InterruptedException the interrupted exception
     */
    @Scheduled(fixedDelay = 1000)
    public void task() throws InterruptedException {
        System.out.println("Thread Name : "
                + Thread.currentThread().getName()
                + "  i am a task : date ->  "
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        Thread.sleep(5000);
    }

    /**
     * The next round of tasks will be executed 2 seconds after the start of this round of tasks Execution time is negligible
     */
    @Scheduled(fixedRate = 2000)
    public void task2() {
        System.out.println("Thread Name : "
                + Thread.currentThread().getName()
                + "  i am a task2 : date ->  "
                + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
    }

}

result:

Thread Name : scheduling-1  i am a task : date ->  2022-03-07 15:30:58
Thread Name : scheduling-1  i am a task2 : date ->  2022-03-07 15:30:58
Thread Name : scheduling-1  i am a task2 : date ->  2022-03-07 15:30:58
Thread Name : scheduling-1  i am a task2 : date ->  2022-03-07 15:30:59
Thread Name : scheduling-1  i am a task : date ->  2022-03-07 15:30:59
Thread Name : scheduling-1  i am a task : date ->  2022-03-07 15:31:04

Result analysis:

In other words, a "chain reaction" occurs due to single thread blocking, which leads to the disorder of task execution@ The enableshcheduling annotation introduces the ScheduledAnnotationBeanPostProcessor, and its setScheduler(Object scheduler) has the following comments:

If taskscheduler or ScheduledExecutorService is not defined as the parameter of this method, the method will find a unique taskscheduler or Bean named taskscheduler in Spring IoC as the parameter. Of course, you can find a ScheduledExecutorService according to the method of finding taskscheduler. If you can't find it, you can only use the local single thread scheduler.

The call order relationship of spring tasks is: the task scheduling thread schedules the task execution thread to execute scheduled tasks, so we define a TaskScheduler according to the above, and provide the automatic configuration of TaskScheduler in Spring Boot automatic configuration:

@ConditionalOnClass({ThreadPoolTaskScheduler.class})
@Configuration(
    proxyBeanMethods = false
)
@EnableConfigurationProperties({TaskSchedulingProperties.class})
@AutoConfigureAfter({TaskExecutionAutoConfiguration.class})
public class TaskSchedulingAutoConfiguration {
    public TaskSchedulingAutoConfiguration() {
    }

    @Bean
    @ConditionalOnBean(
        name = {"org.springframework.context.annotation.internalScheduledAnnotationProcessor"}
    )
    @ConditionalOnMissingBean({SchedulingConfigurer.class, TaskScheduler.class, ScheduledExecutorService.class})
    public ThreadPoolTaskScheduler taskScheduler(TaskSchedulerBuilder builder) {
        return builder.build();
    }

    @Bean
    public static LazyInitializationExcludeFilter scheduledBeanLazyInitializationExcludeFilter() {
        return new ScheduledBeanLazyInitializationExcludeFilter();
    }

    @Bean
    @ConditionalOnMissingBean
    public TaskSchedulerBuilder taskSchedulerBuilder(TaskSchedulingProperties properties, ObjectProvider<TaskSchedulerCustomizer> taskSchedulerCustomizers) {
        TaskSchedulerBuilder builder = new TaskSchedulerBuilder();
        builder = builder.poolSize(properties.getPool().getSize());
        Shutdown shutdown = properties.getShutdown();
        builder = builder.awaitTermination(shutdown.isAwaitTermination());
        builder = builder.awaitTerminationPeriod(shutdown.getAwaitTerminationPeriod());
        builder = builder.threadNamePrefix(properties.getThreadNamePrefix());
        builder = builder.customizers(taskSchedulerCustomizers);
        return builder;
    }
}
# Task scheduling thread pool

# The default size of task scheduling thread pool is 1. It is recommended to increase it according to the task
spring.task.scheduling.pool.size=1
# Scheduling thread name prefix default scheduling-
spring.task.scheduling.thread-name-prefix=scheduling-
# Wait for all tasks to complete when the thread pool is closed
spring.task.scheduling.shutdown.await-termination=
# The maximum waiting time before the scheduling thread is closed to ensure that it must be closed at last
spring.task.scheduling.shutdown.await-termination-period=


# Task execution thread pool configuration

# Whether the core thread is allowed to time out. The thread pool can be reduced and increased dynamically
spring.task.execution.pool.allow-core-thread-timeout=true
#  The core thread pool size is 8 by default
spring.task.execution.pool.core-size=8
# The idle waiting time of thread is 60s by default
spring.task.execution.pool.keep-alive=60s
# The maximum number of thread pools is customized according to the task
spring.task.execution.pool.max-size=
#  Thread pool queue capacity size
spring.task.execution.pool.queue-capacity=
# Wait for all tasks to complete when the thread pool is closed
spring.task.execution.shutdown.await-termination=true
# The maximum waiting time before the execution thread is closed to ensure that it must be closed at last
spring.task.execution.shutdown.await-termination-period=
# Thread name prefix
spring.task.execution.thread-name-prefix=task-

After configuration, you will find that scheduled tasks can be executed in parallel and asynchronously.

2.2 Timer

Timer: This is java. Com that comes with java util. Timer class, which allows you to schedule a java util. TimerTask task. In this way, you can make your program execute at a certain frequency, but it can't run at a specified time. Generally used less.

public class TestTimer {

    public static void main(String[] args) {

        TimerTask timerTask = new TimerTask() {
            @Override
            public void run() {
                System.out.println("task  run:"+ new Date());
            }

        };

        Timer timer = new Timer();

        //Schedule the specified task to start repeated fixed delay execution at the specified time. This is performed every 3 seconds
        timer.schedule(timerTask,10,3000);
    }

}

2.3 ScheduledExecutorService

ScheduledExecutorService: also jdk's own class; It is a scheduled task class designed based on thread pool. Each scheduled task will be assigned to a thread in the thread pool for execution, that is, tasks are executed concurrently and do not affect each other.

public class TestScheduledExecutorService {

    public static void main(String[] args) {

        ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();

        // Parameters: 1. Task body 2. Delay time of first execution
        //      3. Task execution interval 4. Interval time unit
        service.scheduleAtFixedRate(()->System.out.println("task ScheduledExecutorService "+new Date()), 0, 3, TimeUnit.SECONDS);
    }
}

Keywords: Java MySQL Spring Algorithm

Added by danoli on Mon, 07 Mar 2022 10:51:20 +0200