Springboot timer multithreading solves the problem of multiple timer conflicts

Usage scenario:

  1. Our order service generally has an order to be paid, which has a time limit. For example, Alibaba's order is five days, Taobao's order is one day, pinduoduo's order is one day, and meituan's order is 15 minutes
  2. In the fund system, how to update the fund information in multiple storage partitions at the same time

Generally speaking, in the actual development, timers need to solve the problem of simultaneous concurrency of multiple timers and the conflict between timers

It's not a big problem. When it comes to concurrency, it's inseparable from multithreading... Take your time to understand

Problem scenario reproduction:


We can clearly see that the execution results are all scheduling-1
It can be determined from this that the Springboot timer is single threaded by default

But the problem comes. If a thread takes a long time to execute after the thread competes for resources, what about other timers? They can only enter the waiting state. The longer the time, the more timers to wait, which is easy to cause an avalanche

In fact, you only need to add a configuration class and annotate it to solve the problem

adding annotations

The specific codes are as follows:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

@Component
public class SchedulerTaskController {
    private Logger logger= LoggerFactory.getLogger(SchedulerTaskController.class);
    private static final SimpleDateFormat dateFormat=new SimpleDateFormat("HH:mm:ss");
    private int count=0;
    @Scheduled(cron="*/6 * * * * ?")
    @Async("threadPoolTaskExecutor")
    public void process(){
        logger.info("english:this is scheduler task runing "+(count++));
    }

    @Scheduled(fixedRate = 6000)
    @Async("threadPoolTaskExecutor")
    public void currentTime(){
        logger.info("chinese:present time"+dateFormat.format(new Date()));
    }
}

The configuration classes are as follows:

The specific codes are as follows:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.ThreadPoolExecutor;



/**When using multithreading, we often need to create Thread class or implement Runnable interface. If we want to use Thread pool, we also need to create Executors,
 * In the use of spring, it has given us good support. You can use multithreading whenever you want @ EnableAsync
 * The thread pool can be used through the ThreadPoolTaskExecutor provided by spring.*/
//@Configuration indicates that this class is a configuration class
@Configuration
@EnableAsync
//All scheduled tasks are placed in a thread pool. Different threads are used when scheduled tasks are started.
public class TaskScheduleConfig {
    private static final int corePoolSize = 10;       		// Default number of threads
    private static final int maxPoolSize = 100;			    // Maximum number of threads
    private static final int keepAliveTime = 10;			// Allow the idle time of the thread (unit: the default is seconds), and close the thread after ten seconds
    private static final int queueCapacity = 200;			// Number of buffer queues
    private static final String threadNamePrefix = "it-is-threaddemo-"; // Thread pool name prefix

    @Bean("threadPoolTaskExecutor") // The name of the bean. The default method name is lowercase
    public ThreadPoolTaskExecutor getDemoThread(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(corePoolSize);
        executor.setMaxPoolSize(maxPoolSize);
        executor.setQueueCapacity(keepAliveTime);
        executor.setKeepAliveSeconds(queueCapacity);
        executor.setThreadNamePrefix(threadNamePrefix);

        //Processing strategy of thread pool rejecting tasks
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        //initialization
        executor.initialize();

        return executor;
    }
}

Then we can see clearly

As mentioned above, it solves the problem of using multithreading to solve the conflict of multiple timers in Springboot

Posted by freeme on Thu, 19 May 2022 07:45:45 +0300