catalogue
Thread pool
Thread pool is to create some threads first, and their collection is called thread pool. Using thread pool can improve performance. When the system starts, the thread pool creates a large number of idle threads. The program passes a task to the thread pool, and the thread pool will start a thread to execute the task. After execution, the thread will not die, but return to the thread pool to become idle again and wait for the execution of the next task.
Global thread pool
For spring boot, it is very convenient to configure the global thread pool. Add the configuration to initialize a thread pool
@Configuration @EnableAsync public class ExecutorConfig { @Bean("new_Thread") public Executor carSocketExecutor() { //Gets the number of cores for the current machine int cpuNum = Runtime.getRuntime().availableProcessors(); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //Configure the number of core threads executor.setCorePoolSize(cpuNum); //Configure maximum threads executor.setMaxPoolSize(cpuNum * 2); //Configure queue size executor.setQueueCapacity(100); //Thread lifetime executor.setKeepAliveSeconds(60); //Configure the name prefix of threads in the thread pool executor.setThreadNamePrefix("new_Thread"); // CALLER_RUNS: the task is not executed in the new thread, but in the thread of the caller executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //Perform initialization executor.initialize(); return executor; }
If the returned value is tested here, the return value type is Future. The @ Async annotation indicates that the method obtains threads from the thread pool for execution, and the thread pool name is not required
@Override @Async("new_Thread") public Future<String> testService01() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return new AsyncResult<String>("test01 Execution complete!"); } @Override @Async("new_Thread") public Future<String> testService02() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return new AsyncResult<String>("test02 Execution complete!"); } @Override @Async("new_Thread") public Future<String> testService03() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return new AsyncResult<String>("test03 Execution complete!"); }
Test methods. Because of multithreading, the main thread will not wait for the return value of each method, so first put the return value results into a collection until all methods start to execute, and then traverse them. The get () method in Future can get the real return value. Only when this method is called, The main thread will wait for the result in the method to return
@GetMapping("/test01") public StringBuilder test01() { //Return result set List<Future<String>> results = new ArrayList<>(); //Response results StringBuilder restStr = new StringBuilder(); //start time Long startTime = System.currentTimeMillis(); results.add(multithreadingService.testService01()); results.add(multithreadingService.testService02()); results.add(multithreadingService.testService03()); for (Future<String> result : results) { try { restStr.append(result.get()).append("\n"); } catch (Exception e) { e.printStackTrace(); } } //End time Long endTime = System.currentTimeMillis(); restStr.append("Shared time").append(endTime - startTime).append("ms"); return restStr; }
Looking at the test results, we can see that the three methods share about 10s. At the beginning, I set the execution time of each method to 10s, so The test was successful!
Local thread pool
Creating a local thread pool can be implemented using the methods in the Executors class. This article demonstrates the creation of a fixed length thread pool
The test method is the same as the previous global thread pool
@Override public String testService04() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return "test04 Execution complete!"; } @Override public String testService05() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return "test05 Execution complete!"; } @Override public String testService06() { try { System.out.println("Thread name " + Thread.currentThread().getName()); Thread.sleep(10000L); } catch (InterruptedException e) { e.printStackTrace(); } return "test06 Execution complete!"; }
@GetMapping("/test02") public StringBuilder test02() { //Return result set List<Future<String>> results = new ArrayList<>(); //Response results StringBuilder restStr = new StringBuilder(); //start time Long startTime = System.currentTimeMillis(); //Create a fixed length thread pool (indicating that the maximum concurrency is 3, and wait if the queue exceeds 3) ExecutorService executorService = Executors.newFixedThreadPool(POOL_COUNT, new MyThreadFactory("my_thread")); results.add(executorService.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.interrupted(); return multithreadingService.testService04(); } })); results.add(executorService.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.interrupted(); return multithreadingService.testService05(); } })); results.add(executorService.submit(new Callable<String>() { @Override public String call() throws Exception { Thread.interrupted(); return multithreadingService.testService06(); } })); for (Future<String> result : results) { try { restStr.append(result.get()).append("\n"); } catch (Exception e) { e.printStackTrace(); } finally { //Close thread pool executorService.shutdown(); } } //End time Long endTime = System.currentTimeMillis(); restStr.append("Shared time").append(endTime - startTime).append("ms"); return restStr; }
The thread factory here mainly gives a name to the thread. In addition, some log information such as thread creation time and end time can be added according to business requirements
@Data public class MyThreadFactory implements ThreadFactory { //Thread name private String poolName; //Thread number private int threadCount; public MyThreadFactory(String poolName) { this.poolName = poolName; threadCount = 0; } @Override public Thread newThread(Runnable runnable) { threadCount++; return new Thread(runnable, poolName + "_" +threadCount); }
test result