spring boot uses a custom configured thread pool to perform Async asynchronous tasks

  • 2020-12-21 18:05:06
  • OfStack

In the previous blog, https: / / www ofstack. com article / 106718 htm we used spring boot asynchronous operations, at the time, we are using the default thread pool, but if we want to according to the project to customize your own thread pool, here he said it, how to customize the thread pool!

1. Add the configuration properties class


package com.chhliu.springboot.async.configuration; 
import org.springframework.boot.context.properties.ConfigurationProperties; 
 
@ConfigurationProperties(prefix = "spring.task.pool") //  The annotation of locations Has been enabled, and will now load first whenever it is in the environment  
public class TaskThreadPoolConfig { 
 private int corePoolSize; 
 
 private int maxPoolSize; 
 
 private int keepAliveSeconds; 
 
 private int queueCapacity; 
  
  ..................... omit getter,setter Methods.....................  
} 

2. Create a thread pool


package com.chhliu.springboot.async.pool; 
import java.util.concurrent.Executor; 
import java.util.concurrent.ThreadPoolExecutor; 
import org.springframework.beans.factory.annotation.Autowired; 
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 com.chhliu.springboot.async.configuration.TaskThreadPoolConfig; 
 
@Configuration 
@EnableAsync 
public class TaskExecutePool { 
 
 @Autowired 
 private TaskThreadPoolConfig config; 
 
 @Bean 
 public Executor myTaskAsyncPool() { 
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  executor.setCorePoolSize(config.getCorePoolSize()); 
  executor.setMaxPoolSize(config.getMaxPoolSize()); 
  executor.setQueueCapacity(config.getQueueCapacity()); 
  executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); 
  executor.setThreadNamePrefix("MyExecutor-"); 
 
  // rejection-policy : when pool Has been reached max size How do you handle new tasks  
  // CALLER_RUNS : The task is not executed in the new thread, but by the caller's own thread  
  executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
  executor.initialize(); 
  return executor; 
 } 
} 

3. Enable configuration support in the main class


package com.chhliu.springboot.async; 
import org.springframework.boot.SpringApplication; 
import org.springframework.boot.autoconfigure.SpringBootApplication; 
import org.springframework.boot.context.properties.EnableConfigurationProperties; 
import org.springframework.scheduling.annotation.EnableAsync; 
 
import com.chhliu.springboot.async.configuration.TaskThreadPoolConfig; 
 
@SpringBootApplication 
@EnableAsync 
@EnableConfigurationProperties({TaskThreadPoolConfig.class} ) //  Enable configuration property support  
public class SpringbootAsyncApplication { 
 
 public static void main(String[] args) { 
  SpringApplication.run(SpringbootAsyncApplication.class, args); 
 } 
} 

4. The test class


package com.chhliu.springboot.async.pool; 
 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.scheduling.annotation.Async; 
import org.springframework.stereotype.Component; 
 
@Component 
public class AsyncTask { 
 protected final Logger logger = LoggerFactory.getLogger(this.getClass()); 
  
 @Async("myTaskAsyncPool") //myTaskAsynPool That is, configure the thread pool method name. If you do not write the custom thread pool method name here, the default thread pool will be used  
 public void doTask1(int i) throws InterruptedException{ 
  logger.info("Task"+i+" started."); 
 } 
} 

5. Test


package com.chhliu.springboot.async; 
import java.util.concurrent.ExecutionException; 
import org.junit.Test; 
import org.junit.runner.RunWith; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.boot.test.context.SpringBootTest; 
import org.springframework.test.context.junit4.SpringRunner; 
 
import com.chhliu.springboot.async.pool.AsyncTask; 
 
@RunWith(SpringRunner.class) 
@SpringBootTest 
public class SpringbootAsyncApplicationTests { 
 protected final Logger logger = LoggerFactory.getLogger(this.getClass()); 
 @Autowired 
 private AsyncTask asyncTask; 
 
 @Test 
 public void AsyncTaskTest() throws InterruptedException, ExecutionException { 
 
  for (int i = 0; i < 100; i++) { 
   asyncTask.doTask1(i); 
  } 
 
  logger.info("All tasks finished."); 
 } 
} 

The test results are as follows:


2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-10] c.c.springboot.async.pool.AsyncTask  : Task60 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-25] c.c.springboot.async.pool.AsyncTask  : Task61 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-6] c.c.springboot.async.pool.AsyncTask  : Task62 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-23] c.c.springboot.async.pool.AsyncTask  : Task63 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-20] c.c.springboot.async.pool.AsyncTask  : Task64 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-19] c.c.springboot.async.pool.AsyncTask  : Task65 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-16] c.c.springboot.async.pool.AsyncTask  : Task66 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-15] c.c.springboot.async.pool.AsyncTask  : Task67 started. 
2017-03-20 20:15:15.208 INFO 4068 --- [ MyExecutor-12] c.c.springboot.async.pool.AsyncTask  : Task68 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-1] c.c.springboot.async.pool.AsyncTask  : Task69 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-11] c.c.springboot.async.pool.AsyncTask  : Task81 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-8] c.c.springboot.async.pool.AsyncTask  : Task82 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-7] c.c.springboot.async.pool.AsyncTask  : Task83 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-4] c.c.springboot.async.pool.AsyncTask  : Task84 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-29] c.c.springboot.async.pool.AsyncTask  : Task85 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-21] c.c.springboot.async.pool.AsyncTask  : Task86 started. 
2017-03-20 20:15:15.209 INFO 4068 --- [ MyExecutor-17] c.c.springboot.async.pool.AsyncTask  : Task88 started. 

Test results ok!

6. Configure the default thread pool

If we want to use the default thread pool, but just want to change the configuration of the default thread pool, then we need to implement the AsyncConfigurer class. The example code is as follows:


import java.lang.reflect.Method; 
import java.util.concurrent.Executor; 
import java.util.concurrent.ThreadPoolExecutor; 
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.scheduling.annotation.AsyncConfigurer; 
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; 
import com.chhliu.cq.emailservice.threadconfiguration.TaskThreadPoolConfig; 
import lombok.extern.slf4j.Slf4j; 
 
/** 
 *  Note: This thread pool is shared by all asynchronous tasks and does not belong to 1 Asynchronous tasks  
 *  Description: Configure thread pools for asynchronous tasks  
 * @author chhliu 
 *  Creation time: 2017 years 5 month 22 day   In the morning 10:20:56 
 * @version 1.2.0 
 */ 
@Slf4j 
@Configuration 
public class AsyncTaskExecutePool implements AsyncConfigurer{ 
 
 @Autowired 
 private TaskThreadPoolConfig config; //  To configure the property class, see the code above  
 
 @Override 
 public Executor getAsyncExecutor() { 
  ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
  executor.setCorePoolSize(config.getCorePoolSize()); 
  executor.setMaxPoolSize(config.getMaxPoolSize()); 
  executor.setQueueCapacity(config.getQueueCapacity()); 
  executor.setKeepAliveSeconds(config.getKeepAliveSeconds()); 
  executor.setThreadNamePrefix("taskExecutor-"); 
 
  // rejection-policy : when pool Has been reached max size How do you handle new tasks  
  // CALLER_RUNS : The task is not executed in the new thread, but by the caller's own thread  
  executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); 
  executor.initialize(); 
  return executor; 
 } 
 
 @Override 
 public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {//  Exception handling in asynchronous tasks  
  return new AsyncUncaughtExceptionHandler() { 
    
   @Override 
   public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) { 
    log.error("=========================="+arg0.getMessage()+"=======================", arg0); 
    log.error("exception method:"+arg1.getName()); 
   } 
  }; 
 } 
} 

To use it, simply add @Async to the method.


Related articles: