除了之前介紹的創建線程方式外,spring boot為我們了提供一套完整的線程創建方式,其中包括了:線程、線程池、線程的監控。
一、使用spring boot提供的方法創建線程與線程池
1.首先在spring boot 的啟動類上加上注解:@EnableAsync
//開啟異步線程必須加上注解
@EnableAsync @SpringBootApplication public class ThemApplication { public static void main(String[] args) { SpringApplication.run(ThemApplication.class, args); } }
2.spring boot創建的線程,需要我們先創建線程池
/** * 線程池的配置 * * 需要加上這兩個注解 */ @Configuration @EnableAsync public class Pool implements AsyncConfigurer { @Bean("thread") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設置核心線程數
executor.setCorePoolSize(5); // 設置最大線程數
executor.setMaxPoolSize(10); // 設置隊列容量
executor.setQueueCapacity(20); // 設置線程活躍時間(秒)
executor.setKeepAliveSeconds(60); // 設置線程名稱
executor.setThreadNamePrefix("hello-"); // 設置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務結束后再關閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true); return executor; } }
3.不帶返回值的線程任務創建,線程任務創建很方便,只需要在線程方法使用@Async注解就行,並且把這個類交給spring來管理
@Configuration public class UseTask { @Async public void show(int i) { System.out.println("線程" +i + " 執行異步任務:" ); } }
測試的結果:
4.帶返回值的線程任務創建
帶返回值的線程需要實現Future<T>方法,T表示返回的類型
@Configuration public class UseTask { //帶返回值的線程
@Async public Future<Integer> showSum(int i,int j) { int x=i+j; System.out.println("當前執行的是第"+i+"線程"); return new AsyncResult<Integer>(x); } }
可以看到這個方法返回的是一個Future<Integer>,所以我們要通過這個類中的get方法獲取返回值
@Test public void thread() throws ExecutionException, InterruptedException { int j = 0; for (int i = 0; i < 10; i++) { //返回的類型 Future<Integer> num = useTask.showSum(i, i); //get方法獲取返回值 j = num.get(); System.out.println("計算結果是" + j); } }
二、spring boot線程池的監控
springboot中監控線程的操作非常簡便,只需要繼承ThreadPoolTaskExecutor類就能實現
/** * 監控線程的類很簡單,只需要繼承ThreadPoolTaskExecutor * */ @Configuration public class Monitor extends ThreadPoolTaskExecutor { /** * 創建一個線程安全的ConcurrentHashMap,存儲監控的信息 */
public ConcurrentHashMap<String, ThreadPoolTaskExecutor> threadPoolMap = new ConcurrentHashMap<>(); }
監控類創建好后,還需要在線程池配置中聲明。修改后的pool類
/** * 線程池的配置 * * 需要加上這兩個注解 */ @Configuration @EnableAsync public class Pool implements AsyncConfigurer { @Autowired Monitor monitor; @Bean("thread") public Executor taskExecutor() { ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); // 設置核心線程數
executor.setCorePoolSize(5); // 設置最大線程數
executor.setMaxPoolSize(10); // 設置隊列容量
executor.setQueueCapacity(20); // 設置線程活躍時間(秒)
executor.setKeepAliveSeconds(60); // 設置線程名稱
executor.setThreadNamePrefix("hello-"); // 設置拒絕策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy()); // 等待所有任務結束后再關閉線程池
executor.setWaitForTasksToCompleteOnShutdown(true); //配置線程池到線程監控類中,第一個參數為線程池的名稱
monitor.threadPoolMap.put("thread", executor); return executor; } }
編寫測試類,獲取線程的監控數據
@RestController public class Test { @Autowired UseTask useTask; @Autowired Monitor monitor; @RequestMapping(value="/test",method= RequestMethod.GET) public void meetInitMain() throws InterruptedException { //線程任務的創建
useTask.show(1); useTask.show(2); useTask.show(3); useTask.show(4); useTask.show(5); //獲取監控的信息,從threadPoolMap中得到在線程池配置類中put進去的線程池名稱
ThreadPoolTaskExecutor monitorTask = monitor.threadPoolMap.get("thread"); //threadPoolExecutor才是線程監控的信息存儲類
ThreadPoolExecutor threadPoolExecutor= monitorTask.getThreadPoolExecutor(); //當前線程池中的工作線程數
int poolSize=threadPoolExecutor.getPoolSize(); //隊列中的任務
int queueSize=threadPoolExecutor.getQueue().size(); //線程正在執行的任務
int activeCount=threadPoolExecutor.getActiveCount(); //已經執行完成的任務
Long completedTaskCount=threadPoolExecutor.getCompletedTaskCount(); //全部的任務數
Long taskCount=threadPoolExecutor.getTaskCount(); //線程池中曾經最大的線程數量
int largestPoolSize= threadPoolExecutor.getLargestPoolSize(); Thread.sleep(100); System.out.println("當前線程池中的工作線程數:"+poolSize+" 隊列中的任務有:"
+queueSize+" 正在執行的任務:"+activeCount +" 已經執行完成的任務:"+completedTaskCount+" 全部的任務數:"+taskCount +"線程池中曾經最大的線程數量:"+largestPoolSize); } }
連續請求兩次測試地址,測試結果: