java並發學習--第二章 spring boot實現線程的創建


除了之前介紹的創建線程方式外,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); } }

 

  連續請求兩次測試地址,測試結果:

 

 

   

  

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM