Springboot Table Pool Service Battle Share

We often use the thread pool service provided by ThreadPoolExecutor. The springboot framework provides @Async annotation to help us more easily submit business logic to the thread pool for asynchronous execution. Today we will experience this thread pool service in action;
Practical environment
winddowns10;
jdk1.8;
springboot 1.5.9.RELEASE;
Development tools: IntelliJ IDEA;

There are multiple projects in this, the project used this time is threadpooldemoserver, as shown in the red box in the following figure:
Combine the actual combat steps
The actual combat steps are as follows:
Create springboot project;
Create the interface and implementation of the Service layer;
Create a controller, develop an http service interface, which will call the service layer services;
Create the configuration of the thread pool;
Asynchronize the service of the Service layer, so that every call will be submitted to the thread pool for asynchronous execution;
Extend ThreadPoolTaskExecutor, you can observe the current thread pool situation when submitting tasks to the thread pool;
Create a springboot project
Use IntelliJ IDEA to create a springboot web project threadpooldemoserver. The content of pom.xml is as follows:


xsi: schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0< /modelVersion>
com.bolingcavalry
threadpool demoserver
0.0.1-SNAPSHOT
jar
threadpooldemoserver
< description>Demo project for Spring Boot

org.springframework.boot
spring-boot-starter-parent
1.5.9.RELEASE


< properties>
UTF-8
UTF-8
1.8



org.springframework.boot
spring-boot-starter-web





org.springframework.boot
spring-boot-maven-plugin



Create service layer interface and implementation
Create a service layer interface AsyncService , As follows:

public interface AsyncService {

/**
* Execute asynchronous tasks
*/
void executeAsync();
}

The corresponding AsyncServiceImpl is implemented as follows:

@Service
public class AsyncServiceImpl implements AsyncService {

private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class);

@Override
public void executeAsync() {
logger.info("start executeAsync");
try{< br /> Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace();
}
logger.info("end executeAsync");
}
}

This method is very simple Single: sleep for one second;
Create a controller
Create a controller as Hello, define an http interface inside, and call the service of the Service layer, as follows:

@RestController< br />public class Hello {

private static final Logger logger = LoggerFactory.getLogger(Hello.class);

@Autowired
private AsyncService asyncService;

@RequestMapping("/")
public String submit(){
logger.info("start submit");

//Call the service layer
asyncService.executeAsync();

logger.info("end submit");

return "success";
}
}

At this point, we have completed an http request service, and the things that are done inside are actually synchronized. Next, we will start to configure the springboot thread pool service and set the service layer to do things. All are submitted to the thread pool for processing;
springboot thread pool configuration
Create a configuration class ExecutorConfig to define how to create a ThreadPoolTaskExecutor, use the two annotations @Configuration and @EnableAsync to indicate that this is a configuration Class, and is the configuration class of the thread pool, as shown below:

@Configuration
@EnableAsync
public class ExecutorConfig {

private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class) ;

@Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//Configure the number of core threads
executor.setCorePoolSize(5);
//Configure the maximum number of threads
executor.setMaxPoolSize(5);
//Configure the queue size
executor.setQueueCapacity(99999);
//Configure the name prefix of threads in the thread pool
executor.setThreadNamePrefix("async-service-");

// rejection-policy: How to handle new tasks when the pool has reached max size
// CALLER_RUNS: Do not execute tasks in a new thread, but have the caller’s thread to execute
executor.setRejectedExecutionHandler( new ThreadPoolExecutor.CallerRunsPolicy());
//Execute initialization
executor.initialize();
return executor;
}
}

Note that the name of the above method is asyncServiceExecutor, which will be used soon;
Asynchronize the service of the Service layer
Open AsyncServiceImpl.java, add the annotation @Async(“asyncServiceExecutor”) to the executeAsync method, and asyncServiceExecutor is the front ExecutorConfig. The method name in java indicates that the thread pool entered by the executeAsync method was created by the asyncServiceExecutor method, as follows:

@Override
@Async("asyncServiceExecutor")
public void executeAsync() {
logger.info("start executeAsync");
try{
Thread.sleep(1000);
}catch(Exception e){
e.printStackTrace ();
}
logger.info("end executeAsync");
}

Verification effect
Run this springboot (the file where pom.xml is located Execute mvn spring-boot:run under the folder);
Enter in the browser: http://localhost:8080;
Use the F5 button in the browser to refresh several times quickly;
See it in the springboot console The log is as follows:

2018-01-21 22:43:18.630 INFO 14824 --- [nio-8080-exec-8] cbtcontroller.Hello: start submit
2018-01-21 22:43:18.630 INFO 14824 --- [nio-8080-exec-8] cbtcontroller.Hello: end submit
2018-01-21 22:43:18.929 INFO 14824 --- [async-service- 1] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:18.930 INFO 14824 --- [async-service-1] cbtservice.i mpl.AsyncServiceImpl: start executeAsync
2018-01-21 22:43:19.005 INFO 14824 --- [async-service-2] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:19.006 INFO 14824 --- [async-service-2] cbtservice.impl.AsyncServiceImpl: start executeAsync
2018-01-21 22:43:19.175 INFO 14824 --- [async-service- 3] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:19.175 INFO 14824 --- [async-service-3] cbtservice.impl.AsyncServiceImpl: start executeAsync
2018-01-21 22:43:19.326 INFO 14824 --- [async-service-4] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:19.495 INFO 14824 --- [async-service-5] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:19.930 INFO 14824 --- [async-service-1] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 22:43:20.006 INFO 14824 --- [async-service-2] cbtservice.impl.AsyncS erviceImpl: end executeAsync
2018-01-21 22:43:20.191 INFO 14824 --- [async-service-3] cbtservice.impl.AsyncServiceImpl: end executeAsync

As shown in the above log , We can see that the execution thread of the controller is “nio-8080-exec-8”, which is the execution thread of tomcat, and the service layer log shows that the thread is named “async-service-1”, which is obviously already configured in us Executed in the thread pool, and in each request, the start and end logs of the controller are continuously printed, indicating that each request is responded quickly, and time-consuming operations are left to the threads in the thread pool to execute asynchronously;
Extending ThreadPoolTaskExecutor
Although we have used the thread pool, it is not clear what the thread pool was at that time. How many threads are executing and how many are waiting in the queue? Here I created a subclass of ThreadPoolTaskExecutor, which will print out the current thread pool running status every time a thread is submitted. The code is as follows:

public class VisiableThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {
private static final Logger logger = LoggerFactory.getLogger(VisiableThreadPoolTaskExecutor.class);

private void showThreadPoolInfo(String prefix){
ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor();

if( null==threadPoolExecutor){
return;
}

logger.info("{}, {},taskCount [{}], completedTaskCount [{}], activeCount [ {}], queueSize [{}]",
this.getThreadNamePrefix(),
prefix,
threadPoolExecutor.getTaskCount(),
threadPoolExecutor.getCompletedTaskCount(),
threadPoolExecutor.getActiveCount(),
threadPoolExecutor.getQueue().size());
}

@Override
public void execute(Runnable t ask) {
showThreadPoolInfo("1. do execute");
super.execute(task);
}

@Override
public void execute (Runnable task, long startTimeout) {
showThreadPoolInfo("2. do execute");
super.execute(task, startTimeout);
}

@Override
public Future submit(Runnable task) {
showThreadPoolInfo("1. do submit");
return super.submit(task);
}

@Override
public Future submit(Callable task) {
showThreadPoolInfo("2. do submit");
return super.submit( task);
}

@Override
public ListenableFuture submitListenable(Runnable task) {
showThreadPoolInfo("1. do submitListenable");
return super.submitListenable(task);
}

@Override
public ListenableFuture submitListenable(Callable task) {
showThreadPo olInfo("2. do submitListenable");
return super.submitListenable(task);
}
}

As shown above, in the showThreadPoolInfo method, the total number of tasks, The number of completed, active threads, and queue size are all printed, and then the execute, submit and other methods of the parent class are overridden, and the showThreadPoolInfo method is called inside, so that every time a task is submitted to the thread pool, the current thread will be The basic information of the pool is printed in the log;
Modify the asyncServiceExecutor method of ExecutorConfig.java, change ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor() to ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(), as shown below:

@ Bean
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
//Use VisiableThreadPoolTaskExecutor
ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor();
/ /Configure the number of core threads
executor.setCorePoolSize(5);
//Configure the maximum number of threads
executor.setMaxPoolSize(5);
//Configure the queue size
executor.setQueueCapacity(99999);
//Configure the name prefix of threads in the thread pool
executor.setThreadNamePrefix("async-service-");

// rejection-policy: how to deal with new tasks when the pool has reached max size
// CALLER_RUNS: do not execute tasks in a new thread, but have the thread of the caller to execute
/> executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//execute initialization
executor.initialize();
return executor;
}

Start the project again, and refresh http://localhost:8080 in the browser repeatedly, and the logs you see are as follows:

2018-01-21 23:04:56.113 INFO 15580 --- [nio- 8080-exec-1] cbteVisiableThreadPoolTaskExecutor: async-service-, 2. do submit,taskCount [99], completedTaskCount [85], activeCount [5], queueSize [9]
2018-01-21 23:04 :56.113 INFO 15580 --- [nio-8080-exec-1] cbtcontroller.Hello: end submit
2018-01-21 23:04:56.225 INFO 15580 --- [async-service-1] cbt service.impl.AsyncServiceImpl: end executeAsync
2018-01-21 23:04:56.225 INFO 15580 --- [async-service-1] cbtservice.impl.AsyncServiceImpl: start executeAsync
2018-01 -21 23:04:56.240 INFO 15580 --- [nio-8080-exec -2] cbtcontroller.Hello: start submit
2018-01-21 23:04:56.240 INFO 15580 --- [nio-8080-exec-2] cbteVisiableThreadPoolTaskExecutor: async-service-, 2. do submit ,taskCount [100], completedTaskCount [86], activeCount [5], queueSize [9]
2018-01-21 23:04:56.240 INFO 15580 --- [nio-8080-exec-2] cbtcontroller .Hello: end submit
2018-01-21 23:04:56.298 INFO 15580 --- [async-service-2] cbtservice.impl.AsyncServiceImpl: end executeAsync
2018-01-21 23 :04:56.298 INFO 15580 --- [async-service-2] cbtservice.impl.AsyncServiceImpl: start executeAsync
2018-01-21 23:04:56.372 INFO 15580 --- [nio-8080-exec -3] cbtcontroller.Hello: start submit
2018-01-21 23:04:56.373 INFO 15580 --- [nio-8080-exec-3] cbteVisiableThreadPoolTaskExecutor: async-service-, 2. do submit ,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9]
2018-01-21 23:04:56.373 INFO 15580 --- [nio-8080-exec-3] cbtcontroller.Hello: end submit
2018-01-21 23:04:56.444 INFO 15580 --- [async-service-3] cbtservice.impl. AsyncServiceImpl: end executeAsync
2018-01-21 23:04:56.445 INFO 15580 --- [async-service-3] cbtservice.impl.AsyncServiceImpl: start executeAsync

Pay attention to this line of log :2. do submit,taskCount [101], completedTaskCount [87], activeCount [5], queueSize [9] This means that when a task is submitted to the thread pool, the method submit(Callable task) is called, and it has been submitted currently 101 tasks, 87 completed, currently 5 threads are processing tasks, and 9 tasks are waiting in the queue. The basic situation of the thread pool is clear all the way; at this point, the actual combat of the springboot thread pool service is complete, hope Can help you quickly implement asynchronous services in your project.

Leave a Comment

Your email address will not be published.