SpringBoot實現線程池
現在由於系統越來越復雜,導致很多接口速度變慢,這時候就會想到可以利用線程池來處理一些耗時並不影響系統的操作。
新建Spring Boot項目
1. ExecutorConfig.xml
新建線程池配置文件。
@Configuration @EnableAsync public class ExecutorConfig { private static final Logger logger = LoggerFactory.getLogger(ExecutorConfig.class); @Value("${async.executor.thread.core_pool_size}") private int corePoolSize; @Value("${async.executor.thread.max_pool_size}") private int maxPoolSize; @Value("${async.executor.thread.queue_capacity}") private int queueCapacity; @Value("${async.executor.thread.name.prefix}") private String namePrefix; @Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); //配置核心線程數 executor.setCorePoolSize(corePoolSize); //配置最大線程數 executor.setMaxPoolSize(maxPoolSize); //配置隊列大小 executor.setQueueCapacity(queueCapacity); //配置線程池中的線程的名稱前綴 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當pool已經達到max size的時候,如何處理新任務 // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //執行初始化 executor.initialize(); return executor; } }
2. application.yml
@Value配置在application.yml,可以參考配置
# 異步線程配置 async: executor: thread: # 配置核心線程數 core_pool_size: 10 # 配置最大線程數 max_pool_size: 20 # 配置隊列大小 queue_capacity: 99999 # 配置線程池中的線程的名稱前綴 name: prefix: async-service-
3. AsyncService.java
創建一個 Service 接口,是異步線程的接口,將方法寫入其實現類即可
public interface AsyncService { /** * 執行異步任務的方法,參數自己可以添加 */ void executeAsync(); }
4. AsyncServiceImpl.java
實現類,用來寫業務邏輯
@Service public class AsyncServiceImpl implements AsyncService { private static final Logger logger = LoggerFactory.getLogger(AsyncServiceImpl.class); @Override @Async("asyncServiceExecutor") public void executeAsync() { logger.info("start executeAsync"); System.out.println("異步線程執行開始瞭"); System.out.println("可以將耗時的操作放到這裡執行瞭"); logger.info("end executeAsync"); } }
++將 Service 層的服務異步化,在executeAsync()方法上增加註解@Async(“asyncServiceExecutor”),asyncServiceExecutor方法是前面ExecutorConfig.java中的方法名,表明executeAsync方法進入的線程池是asyncServiceExecutor方法創建的。++
5. AsyncController.java
在控制器裡面註入AsyncService,調用其中的方法即可
@Autowired private AsyncService asyncService; @GetMapping("/async") public void async(){ asyncService.executeAsync(); }
6. 用Postman進行測試
打印log入下
2021-06-16 22:15:47.655 INFO 10516 — [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:15:47.655 INFO 10516 — [async-service-5] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:15:47.770 INFO 10516 — [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:15:47.770 INFO 10516 — [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:15:47.816 INFO 10516 — [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:15:47.816 INFO 10516 — [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:15:48.833 INFO 10516 — [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:15:48.834 INFO 10516 — [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:15:48.986 INFO 10516 — [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:15:48.987 INFO 10516 — [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
至此簡單的線程池已經實現瞭。
5. 將當前線程池的運行狀況打印出來
5.1 VisiableThreadPoolTaskExecutor.java
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 task) { 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 <T> Future<T> submit(Callable<T> 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 <T> ListenableFuture<T> submitListenable(Callable<T> task) { showThreadPoolInfo("2. do submitListenable"); return super.submitListenable(task); } }
5.2 修改asyncServiceExecutor.java
修改ExecutorConfig.java的asyncServiceExecutor方法,將ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor()改為ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor()
@Bean(name = "asyncServiceExecutor") public Executor asyncServiceExecutor() { logger.info("start asyncServiceExecutor"); //在這裡修改 ThreadPoolTaskExecutor executor = new VisiableThreadPoolTaskExecutor(); //配置核心線程數 executor.setCorePoolSize(corePoolSize); //配置最大線程數 executor.setMaxPoolSize(maxPoolSize); //配置隊列大小 executor.setQueueCapacity(queueCapacity); //配置線程池中的線程的名稱前綴 executor.setThreadNamePrefix(namePrefix); // rejection-policy:當pool已經達到max size的時候,如何處理新任務 // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行 executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); //執行初始化 executor.initialize(); return executor; }
5.3 使用Postman進行測試
2021-06-16 22:23:30.951 INFO 14088 — [nio-8087-exec-2] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [0], completedTaskCount [0], activeCount [0], queueSize [0]
2021-06-16 22:23:30.952 INFO 14088 — [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:23:30.953 INFO 14088 — [async-service-1] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:23:31.351 INFO 14088 — [nio-8087-exec-3] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [1], completedTaskCount [1], activeCount [0], queueSize [0]
2021-06-16 22:23:31.353 INFO 14088 — [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:23:31.353 INFO 14088 — [async-service-2] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:23:31.927 INFO 14088 — [nio-8087-exec-5] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [2], completedTaskCount [2], activeCount [0], queueSize [0]
2021-06-16 22:23:31.929 INFO 14088 — [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:23:31.930 INFO 14088 — [async-service-3] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
2021-06-16 22:23:32.496 INFO 14088 — [nio-8087-exec-7] u.d.e.e.i.VisiableThreadPoolTaskExecutor : async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]
2021-06-16 22:23:32.498 INFO 14088 — [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : start executeAsync
異步線程執行開始瞭
可以將耗時的操作放到這裡執行瞭
2021-06-16 22:23:32.499 INFO 14088 — [async-service-4] c.u.d.e.executor.impl.AsyncServiceImpl : end executeAsync
可以看到上面async-service-, 2. do submit,taskCount [3], completedTaskCount [3], activeCount [0], queueSize [0]關於線程的信息都打印出來瞭。
到此這篇關於SpringBoot實現線程池的文章就介紹到這瞭,更多相關SpringBoot 線程池內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Spring Boot使用線程池處理上萬條數據插入功能
- springboot @Async 註解如何實現方法異步
- SpringBoot父子線程數據傳遞的五種方案介紹
- 對spring task和線程池的深入研究
- SpringBoot 如何實現異步編程