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();就是永远执行不到。。。。

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