Spring’s own thread pool ThreadPoolTaskExecutor

Spring default thread pool simpleAsyncTaskExecutor
The interface class of Spring asynchronous thread pool is TaskExecutor, which is essentially java.util.concurrent.Executor. If there is no configuration, simpleAsyncTaskExecutor is used by default.

@Async demonstrates Spring’s default simpleAsyncTaskExecutor

@Component
@EnableAsync
public class ScheduleTask {<!-- -->

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Async
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {<!-- -->
        try {<!-- -->
            Thread.sleep(6000);
            System.out.println("Spring1's own thread pool" + Thread.currentThread().getName() + "-" + sdf.format(new Date()));
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }

    @Async
    @Scheduled(cron = "*/2 * * * * ?")
    public void testAsyn() {<!-- -->
        try {<!-- -->
            Thread.sleep(1000);
            System.out.println("Spring2's own thread pool" + Thread.currentThread().getName() + "-" + sdf.format(new Date()));
        } catch (Exception ex) {<!-- -->
            ex.printStackTrace();
        }
    }
}

From the running results, we can see that Spring’s default @Async thread pool name is SimpleAsyncTaskExecutor, and a new thread will be created every time, so you can see that the number following TaskExecutor- will keep getting bigger.

The characteristic of simpleAsyncTaskExecutor is that each time a task is executed, it will restart a new thread and allow developers to control the maximum number of concurrent threads (concurrencyLimit), thus playing a certain role in resource conservation. The default value of concurrencyLimit is -1, which means resource throttling is not enabled.

Spring’s thread pool ThreadPoolTaskExecutor
The above introduces Spring’s default thread pool simpleAsyncTaskExecutor, but Spring recommends that our developers use the ThreadPoolTaskExecutor class to create a thread pool, which is essentially a wrapper for java.util.concurrent.ThreadPoolExecutor.

This class is under the spring package. It is the thread pool class provided by Spring for our developers. Here we focus on the usage of this class.

Spring provides xml for us to configure the ThreadPoolTaskExecutor thread pool, but now SpringBoot is generally used to develop projects, so you can directly configure it through yaml or properties, or you can also use @Configuration configuration. The configuration and use are demonstrated below.

ThreadPoolTaskExecutor configuration
application.properties

Number of core thread pools

spring.task.execution.pool.core-size=5

Maximum number of thread pools

spring.task.execution.pool.max-size=10

Task queue capacity

spring.task.execution.pool.queue-capacity=5

The survival time of non-core threads

spring.task.execution.pool.keep-alive=60

Prefix name of the thread pool

spring.task.execution.thread-name-prefix=god-jiang-task-
AsyncScheduledTaskConfig.java

@Configuration
public class AsyncScheduledTaskConfig {<!-- -->

    @Value("${spring.task.execution.pool.core-size}")
    private int corePoolSize;
    @Value("${spring.task.execution.pool.max-size}")
    private int maxPoolSize;
    @Value("${spring.task.execution.pool.queue-capacity}")
    private int queueCapacity;
    @Value("${spring.task.execution.thread-name-prefix}")
    private String namePrefix;
    @Value("${spring.task.execution.pool.keep-alive}")
    private int keepAliveSeconds;
    @Bean
    public Executor myAsync() {<!-- -->
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //Maximum number of threads
        executor.setMaxPoolSize(maxPoolSize);
        //Number of core threads
        executor.setCorePoolSize(corePoolSize);
        //The size of the task queue
        executor.setQueueCapacity(queueCapacity);
        //Thread prefix name
        executor.setThreadNamePrefix(namePrefix);
        //Thread survival time
        executor.setKeepAliveSeconds(keepAliveSeconds);

        /**
         * Refusal handling policy
         * CallerRunsPolicy(): handed over to the caller thread to run, such as the main thread.
         * AbortPolicy(): throws an exception directly.
         * DiscardPolicy(): Discard directly.
         * DiscardOldestPolicy(): Discard the oldest task in the queue.
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
        //Thread initialization
        executor.initialize();
        return executor;
    }
}

Add the @Async annotation to the method, and then add the annotation @EnableAsync to the @SpringBootApplication startup class or the @Configuration annotation class to start the multi-thread annotation. @Async will enable asynchronous multi-threaded calls for the annotated method. Note that this method Classes must be managed by the Spring container

@Component
@EnableAsync
public class ScheduleTask {<!-- -->

    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Async("myAsync")
    @Scheduled(fixedRate = 2000)
    public void testScheduleTask() {<!-- -->
        try {<!-- -->
            Thread.sleep(6000);
            System.out.println("Spring1's own thread pool" + Thread.currentThread().getName() + "-" + sdf.format(new Date()));
        } catch (InterruptedException e) {<!-- -->
            e.printStackTrace();
        }
    }

    @Async("myAsync")
    @Scheduled(cron = "*/2 * * * * ?")
    public void testAsyn() {<!-- -->
        try {<!-- -->
            Thread.sleep(1000);
            System.out.println("Spring2's own thread pool" + Thread.currentThread().getName() + "-" + sdf.format(new Date()));
        } catch (Exception ex) {<!-- -->
            ex.printStackTrace();
        }
    }
}

As can be seen from the above running results, custom ThreadPoolTaskExecutor can realize thread reuse, and can also control the number of threads and write better multi-threaded concurrent programs.

In addition, you need to pay attention to the following points regarding the invalidation of annotations:

The annotated method must be a public method
The method must be called from another class, that is, from outside the class. Calls from within the class are invalid because the implementation of @Transactional and @Async annotations are based on Spring’s AOP, and the implementation of AOP is based on dynamic proxy pattern is implemented. Then the reason why the annotation is invalid is obvious. It may be because the method is called by the object itself instead of the proxy object, because it does not go through the Spring container.
The return value of an asynchronous method using the annotation @Async can only be void or Future
The detailed explanation of parameters has been commented in the above annotation. Here we focus on explaining the rejection strategy and processing process of Spring thread pool.

Deny policy
The rejectedExecutionHandler parameter field is used to configure the rejection strategy. Commonly used rejection strategies are as follows

AbortPolicy: Handler for rejected tasks, it will throw RejectedExecutionException
CallerRunsPolicy: Handler for rejected tasks, which runs rejected tasks directly in the calling thread of the execute method.
DiscardOldestPolicy: Handler for rejected tasks that discards the oldest unhandled request and retries execute.
DiscardPolicy: Handler for rejected tasks, by default it will discard rejected tasks.
Processing flow
Check whether the core thread pool is full. If not, create a thread to perform the task. Otherwise, perform the second step.
Check whether the task queue is full. If not, store the task in the task queue. Otherwise, proceed to step three.
Check whether the thread pool is full, that is, whether it has reached the maximum number of thread pools. If not, create a thread to execute the task. Otherwise, handle unexecutable tasks according to the policy.

Summarize
This time I shared the configuration and use of Spring’s own thread pool ThreadPoolTaskExecutor, and talked about the parameters and processing flow of the thread pool. Of course, Spring provides the implementation of 7 thread pools. If you are interested, you can learn about it by yourself~~~

https://zhuanlan.zhihu.com/p/346086161