springboot ThreadPoolTaskExecutor 線程池使用

首先配置下 ThreadPoolTaskExecutor:

threadpool:
  core-pool-size: 10
  max-pool-size: 20
  queue-capacity: 1000
  keep-alive-seconds: 600

這個是放在配置文件裏的參數;

接下來看配置類:
 

package com.guardianfreedom.fangwu.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @ClassName:ThreadConfig
 * @description: 線程池配置
 * @author: shen_jian
 * @date: 2019-05-28 19:32
 **/
@Configuration
@EnableAsync
public class ThreadConfig {
  private static final Logger logger = LoggerFactory.getLogger(ThreadConfig.class);

  @Value("${threadpool.core-pool-size}")
  private int corePoolSize;

  @Value("${threadpool.max-pool-size}")
  private int maxPoolSize;

  @Value("${threadpool.queue-capacity}")
  private int queueCapacity;

  @Value("${threadpool.keep-alive-seconds}")
  private int keepAliveSeconds;

  @Bean
  public Executor asyncServiceExecutor() {
    ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
    //配置核心線程數
    executor.setCorePoolSize(corePoolSize);
    //配置最大線程數
    executor.setMaxPoolSize(maxPoolSize);
    //配置隊列大小
    executor.setQueueCapacity(queueCapacity);
    // 空閒的多餘線程最大存活時間
    executor.setKeepAliveSeconds(keepAliveSeconds);
    //配置線程池中的線程的名稱前綴
    executor.setThreadNamePrefix("async-resource-schedule-");

    // rejection-policy:當pool已經達到max size的時候,如何處理新任務
    // CALLER_RUNS:不在新線程中執行任務,而是有調用者所在的線程來執行
    executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
    //執行初始化
    executor.initialize();
    return executor;
  }
}

再接下來看如何使用:

package com.guardianfreedom.fangwu.controller;

import com.guardianfreedom.fangwu.config.ThreadConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import java.util.concurrent.CountDownLatch;

/**
 * @ClassName:TempController
 * @description: TODO
 * @author: shen_jian
 * @date: 2019-05-29 20:21
 **/
@Controller
public class TempController {
  private static final Logger logger = LoggerFactory.getLogger(TempController.class);
  @Resource
  private ThreadConfig threadConfig;

  @RequestMapping(value="/multThread",method = RequestMethod.GET)
  @ResponseBody
  public String multThread(String index){
    CountDownLatch countDownLatch = new CountDownLatch(4);
    for (int xx = 0;xx<4;xx++){
      threadConfig.asyncServiceExecutor().execute(new Runnable() {
        @Override
        public void run() {
          try {
            String result = "A";
            logger.info("線程--> " + index + " 開始");
            for (long i = 0;i < 99999L;i++){
              result += "A";
            }
//            logger.info(result);
            logger.info("線程--> " + index + " 結束");
          } catch (Exception e) {
            e.printStackTrace();
          } finally {
            Long l = countDownLatch.getCount();
//            logger.info("current threads --> " + l);
            countDownLatch.countDown();  // 這個不管是否異常都需要數量減,否則會被堵塞無法結束
          }
        }
      });
    }
    try {
      countDownLatch.await();
      logger.info(index + "所有線程結束");
    } catch (Exception e) {
      logger.error("阻塞異常");
    }
    return index;
  }
}

這裏有個我比較好奇的地方是countDownLatch.await();這個方法他能識別出是哪次調用方法而創建的線程。比較好奇是怎麼做到的。打個比方:我第一次傳入參數index=1然調用方法。然後再傳入參數index=2調用方法。這個時候它會在index=1的線程都結束之後打印異常所有線程結束,在index=2的線程都結束之後打印異常所有線程結束,而不是等Index=1,和Index=2的線程都結束再打印,如果是這樣的話就會報錯因爲它不知道index=?。有大佬看到的話還希望能幫我講解一下是爲啥。

其次這裏 countDownLatch.countDown(); 方法是每次將countDownLatch裏的線程減一。所有創建countDownLatch的時候要將任務數(類似於我這裏for循環次數)和countDownLatch線程數相等,不然不是提前執行countDownLatch.await();就是永遠執行不到。。。。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章