Spring Advanced Use of scheduled Tasks

The previous post, “Spring’s Basic Use of Timed Tasks”, introduced the simple use posture of timed tasks in the Spring environment, and left some questions. This post aims to provide answers to these questions

I. Advanced periodic task

1. Problem summary

The following questions were raised in the previous blog post, and the rest of the article will focus on them

  • When there are multiple scheduled tasks in a project, are they executed in parallel or in serial?
  • If the default is serial
    • Is there an order between scheduled tasks that have the same Crond expression?
    • Does blocking of one task affect subsequent tasks?
    • What can be done if they need to be executed in parallel?
  • If it is executed concurrently
    • Should you create a new thread or reuse it using a thread pool?
    • In concurrent execution, suppose there is a task that executes once per second, but it takes more than 1s to execute, how does the task perform? Do you keep adding new threads to execute or do you wait until the next one is finished?

2. Serial parallel analysis of multiple scheduled tasks

How do you determine if multiple scheduled tasks in a project are executed sequentially or concurrently? The best way to verify this functionality is to write a TestCase, such as defining two timed tasks and writing an infinite loop in one of them to see if the other will execute properly

@Scheduled(cron = "0/1 * * * *?")
public void sc1(a) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
    while (true) {
        Thread.sleep(5000); }}@Scheduled(cron = "0/1 * * * *?")
public void sc2(a) {
    System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}
Copy the code

First of all, we analyze whether the execution of sc1 and SC2 tasks is serial or parallel. Temporarily, we ignore the blocking of SC1 call and whether a new thread is opened to call SC1 again the next second

  • If serial: sc1 prints once, sc2 may print 0 or 1 times
  • If parallel, sc1 prints once and SC2 prints n times

In actual operation, the GIF diagram is shown below

The results of the figure above confirm that by default, multiple scheduled tasks are executed sequentially; If one task is blocked, all other tasks are affected

3. Priority of scheduled tasks

Since it is executed sequentially, what is the priority? Is it fixed every time, or is it random?

It is also easy to verify the above method, the same two tasks, to see if their output is messed up, if task 1 is printed every time and then task 2 is printed, that is fixed priority; Otherwise, every time we dispatch, we don’t know the order

The test code is as follows

@Scheduled(cron = "0/1 * * * *?")
public void sc1(a)  {
    System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
}

@Scheduled(cron = "0/1 * * * *?")
public void sc2(a) {
    System.out.println(Thread.currentThread().getName() + " | sc2 " + System.currentTimeMillis());
}
Copy the code

The measured results are as follows

It is concluded from the output that the order is sequential and does not show a clear priority relationship

4. Parallel scheduling

The next question is I want these tasks to run concurrently. Can I do that?

Of course it can, and it is relatively simple to use. First, add the annotation @enableAsync on the Application to enable asynchronous invocation, and then add the annotation @async on the scheduled task. A simple demo is as follows

@EnableAsync
@EnableScheduling
@SpringBootApplication
public class QuickMediaApplication {

    public static void main(String[] args) {
        SpringApplication.run(QuickMediaApplication.class, args);
    }

    @Scheduled(cron = "0/1 * * * *?")
    @Async
    public void sc1(a)  {
        System.out.println(Thread.currentThread().getName() + " | sc1 "+ System.currentTimeMillis()); }}Copy the code

After executing the above, view the output (in asynchronous scheduling, thread names should theoretically be different)

From the above output, it can be easily concluded that each time a task is scheduled, a new thread is opened to do the task. Therefore, if an infinite loop is written in a timed task, will it cause the whole process to crash?

As an additional note, the number of threads in a single process on Linux is limited by the following command:

ulimit -u
Copy the code

Before testing, take a look at the normal task execution above, as shown in the GIF below. The number of threads is not overly long

Then switch to the dead-loop scheduling, and the actual test is as follows: thread count goes up

So it’s not a good idea to use the default asynchronous call method. You might not even know it, but can you use your own thread pool to manage these asynchronous tasks?

5. Customize thread pools

Using a custom thread pool instead of the default thread management method is a safer, more flexible and less cumbersome way to use thread pools

Use Spring’s thread pool ThreadPoolTaskExecutor directly

@Bean
public AsyncTaskExecutor asyncTaskExecutor(a) {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    executor.setThreadNamePrefix("yhh-schedule-");
    executor.setMaxPoolSize(10);
    executor.setCorePoolSize(3);
    executor.setQueueCapacity(0);
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
    return executor;
}

@Scheduled(cron = "0/1 * * * *?")
@Async
public void sc1(a) throws InterruptedException {
    System.out.println(Thread.currentThread().getName() + " | sc1 " + System.currentTimeMillis());
    while (true) {
        Thread.sleep(1000 * 5); }}Copy the code

The result of the actual demonstration is as follows, up to 10 threads, and the resubmitted task is discarded directly

Briefly, the benefits of using custom thread pools:

  • Allocate thread pool parameters properly
  • The choice of rejection strategy is also interesting (you can handle the “loaded” task however you want)
  • Thread pool naming, for later troubleshooting, will be a great help

6. Summary

Originally this blog post was supposed to be finished yesterday, August 2nd, but the result was that in the production environment at night, in addition to some problems, after solving online problems, it was relatively late and stayed until today, ah, procrastination is also not allowed…

Here’s a summary of scheduled tasks in Spring

  • By default, all scheduled tasks are sequentially scheduled, one thread, and the order of two tasks is not guaranteed even if crond is exactly the same.
  • use@AsyncAnnotations enable scheduled tasks to be scheduled asynchronously; But you need to turn on the configuration and add it on the startup class@EnableAsyncannotations
  • When concurrent execution is enabled, it is recommended to use a custom thread pool instead of the default for the reasons described above

II. The other

Related 0.

  • Spring: The Basics of Timed Tasks

1. A gray Blog: https://liuyueyi.github.io/hexblog.

A gray personal blog, recording all the study and work in the blog, welcome everyone to go to stroll

2. Statement

As far as the letter is not as good as, has been the content, purely one’s own words, because of the limited personal ability, it is hard to avoid omissions and mistakes, such as finding bugs or better suggestions, welcome criticism and correction, not grudging gratitude

  • Micro Blog address: Small Gray Blog
  • QQ: a gray /3302797840

3. Scan attention

Small grey Blog& public number

Knowledge of the planet