Thread pool is often used in the project, 1000 people have 1000 minutes to create a thread pool, first endorse a paragraph from Ali AJVA development specification:

【 Mandatory 】 Thread pools cannot be created by Executors. Use ThreadPoolExecutor to clear the running rules of the thread pool and avoid resource depletion. 1) FixedThreadPool and SingleThreadPool: The allowed request queue length is Integer.MAX_VALUE, which may accumulate a large number of requests and result in OOM. 2) CachedThreadPool and ScheduledThreadPool: the number of threads allowed to create is integer. MAX_VALUE, which may create a large number of threads, resulting in OOM. Today, let’s talk about the use of thread pools in SpringBoot

Use of thread pools via annotations in SpringBoot

Start by creating a custom thread pool

Create a custom thread pool that inherits spring and provides ThreadPoolTaskExecutor for demonstration purposes

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.concurrent.ListenableFuture; import java.util.concurrent.Callable; import java.util.concurrent.Future; public class TestThreadPoolTaskExecutor extends ThreadPoolTaskExecutor { @Override public void execute(Runnable task) { super.execute(task); } @Override public void execute(Runnable task, long startTimeout) { super.execute(task, startTimeout); } @Override public Future<? > submit(Runnable task) { return super.submit(task); } @Override public <T> Future<T> submit(Callable<T> task) { return super.submit(task); } @Override public ListenableFuture<? > submitListenable(Runnable task) { return super.submitListenable(task); } @Override public <T> ListenableFuture<T> submitListenable(Callable<T> task) { return super.submitListenable(task); }}Copy the code

Create a thread Config class and inject it into the Spring container

Create a config class to create our custom thread pool and set the parameters of the thread pool

@Configuration @EnableAsync @Slf4j public class ExecutorConfig { @Bean public Executor asyncServiceExecutor() { log.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new TestThreadPoolTaskExecutor(); // Set the number of core threads executor.setCorePoolSize(5); SetMaxPoolSize (200); / / configuration queue size executor. SetQueueCapacity (10000); / / the name of the configuration of threads in thread pool prefix executor. SetThreadNamePrefix (" test - thread - "); Rejection -policy: how to process a new task when the pool has reached Max size Not in the new thread to perform a task, but with the caller's thread to perform the executor. SetRejectedExecutionHandler (new ThreadPoolExecutor. CallerRunsPolicy ()); // Initialize executor.initialize(); return executor; }}Copy the code

Finally, it’s time to use thread pools through annotations

Using the @async annotation, the method can be added to the thread pool for execution, just like the run and call methods of the thread class.

@Async("asyncServiceExecutor")
Copy the code

@async (“asyncServiceExecutor”), this is the thread pool that we registered with the container. Take a look

Taking a look at the Spring container view, this thread pool object was injected into the container when we registered the thread Config class. Let’s test two methods, one with no return and one with a return value, directly into the code

@Component public class TestTask { @Async("asyncServiceExecutor") public void task1(){ System.out.println(" Test a task 1 with no return value "); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } system.out.println (" Test a task 2 with no return value "); } @async ("asyncServiceExecutor") public Future<String> Task2 (){system.out.println (" test a task with return value 1"); try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } system.out.println (" Test a task 2 with a return value "); Return new AsyncResult<>(thread.currentThread ().getName()); }}Copy the code

There are two tasks in this task class, one that doesn’t return a value, task1, which is the Runable thread, and one that returns a value, task2, which is the Callable thread, so I’m using AsyncResult and I’m returning a value, so let’s see AsyncResult, AsyncResult is spring’s AsyncResult package

It implements the ListenableFuture interface with the following class relationships:

Take a look at the test results for tasks with no return value from Task1

The test classes are as follows:

@RunWith( SpringRunner.class) @SpringBootTest(classes = BootStartApplication.class) public class TestTaskCase { @Autowired private TestTask testTask; @test public void testVoid(){// Test a task with no return value testTask.task1(); Try {system.out. println(" testing task1 with no return value "); Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); }}}Copy the code

The running results are as follows:

The result is that a runable thread has been added to the thread for execution

Take a look at the test results for tasks with return values in Task2

The test classes are as follows:

@RunWith( SpringRunner.class) @SpringBootTest(classes = BootStartApplication.class) public class TestTaskCase { @Autowired private TestTask testTask; @Test public void testVoid(){ Future<String> future = testTask.task2(); System.out.println(" testing task2 with return value "); While (true) {if (future.isdone ()) {system.out.println (" Task2 has completed "); Try {system.out.println ("task2 has completed, return: "+ future.get()); } catch (InterruptedException e) { e.printStackTrace(); } catch (ExecutionException e) { e.printStackTrace(); } break; } system.out. println("task2 has not completed and is waiting "); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); }}}}Copy the code

The isDone() method of the Future is used to determine whether the task is completed.

A callable thread is added to the thread for execution

Let’s move on to adding monitoring to the thread pool

Thread ChiZaiYong, sometimes some problems because of the number of threads, cause some problem come from line, so it is necessary to add some monitoring thread pool, remember we custom the thread, I say it would demonstrate not add logic, we need to monitor is added into it, directly on your code

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.util.concurrent.ListenableFuture; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.ThreadPoolExecutor; public class TestThreadPoolTaskExecutor extends ThreadPoolTaskExecutor { private void showThreadPoolInfo(String method) { ThreadPoolExecutor threadPoolExecutor = getThreadPoolExecutor(); if (null == threadPoolExecutor) { return; System.out.println(" method: "+ method); system.out.println (" method:" + method); System.out.println(" thread prefix name: "+ this.getThreadNamePrefix())); System. The out. Println (" the number of tasks in the thread pool: "+ threadPoolExecutor. GetTaskCount ()); System. The out. Println (" thread pool has been completed on the number of tasks: "+ threadPoolExecutor. GetCompletedTaskCount ()); System. The out. Println (" the number of threads in thread pool: "+ threadPoolExecutor. GetActiveCount ()); System. The out. Println (" thread pool queue length: "+ threadPoolExecutor. GetQueue (). The size ()); } @Override public void execute(Runnable task) { showThreadPoolInfo("executeRunnable"); super.execute(task); } @Override public void execute(Runnable task, long startTimeout) { showThreadPoolInfo("executeRunnableStartTimeout"); super.execute(task, startTimeout); } @Override public Future<? > submit(Runnable task) { showThreadPoolInfo("submitRunnable"); return super.submit(task); } @Override public <T> Future<T> submit(Callable<T> task) { showThreadPoolInfo("submitCallable"); return super.submit(task); } @Override public ListenableFuture<? > submitListenable(Runnable task) { showThreadPoolInfo("submitListenableRunnable"); return super.submitListenable(task); } @Override public <T> ListenableFuture<T> submitListenable(Callable<T> task) { showThreadPoolInfo("submitListenableCallable"); return super.submitListenable(task); }}Copy the code

This attribute can be added as needed. The way to add monitoring can be stored in the database, cache, log, flume, Kafka, etc., plus the monitoring log, let’s look at the results of the test class running:

In this way, each time a task is added to the thread pool, the thread pool properties will be monitored in real time, so that the application running status can be monitored in real time, and online problems can be quickly located and queried

Springboot’s use of thread pools via annotations is all for you. Welcome to share and point out some of the mistakes in the article so that I can understand more.

Thank you!