1、配置文件新增每个线程池的基本参数配置
thread-pool.user-thread.corePoolSize=1 thread-pool.user-thread.maxPoolSize=1 thread-pool.user-thread.keepAliveSeconds=120 thread-pool.user-thread.queueCapacity=1 thread-pool.school-thread.corePoolSize=2 thread-pool.school-thread.maxPoolSize=2 thread-pool.school-thread.keepAliveSeconds=60 thread-pool.school-thread.queueCapacity=2
2、创建线程池类读取配置文件参数
新建一个线程池用到的相关常量或枚举(我这里用的是常量)
/** * 线程池常量 */ public class ThreadPoolConstants { /** * 用户线程前缀 */ public final static String USER_THREAD_PREFIX = "user-thread"; /** * 学校线程前缀 */ public final static String SCHOOL_THREAD_PREFIX = "school-thread"; /** * 线程池bean后缀名 */ public final static String THREA_BEAN_SUFFIX = "-exector-bean"; /** * 运行线程名称后缀 */ public final static String RUNNING_THREAD_SUFFIX = "-pool-task-"; /** * 线程参数配置-核线程数 */ public final static String THREAD_POOL_CORE_SIZE = "corePoolSize"; /** * 线程参数配置-最大线程数 */ public final static String THREAD_POOL_MAX_SIZE = "maxPoolSize"; /** * 线程参数配置-线程存活时长 */ public final static String THREAD_POOL_KEEP_ALIVE = "keepAliveSeconds"; /** * 线程参数配置-队列长度 */ public final static String THREAD_POOL_QUEUE_CAPACITY = "queueCapacity"; }
线程池抽象类
/** * 线程池抽象类 */ @Data public abstract class AbstractExecutorPool { private int corePoolSize; private int maxPoolSize; private int keepAliveSeconds; private int queueCapacity; }
用户线程池
/** * 用户线程池参数类 */ @Component @ConfigurationProperties(prefix = "thread-pool.user-thread") @Data public class UserThreadPool extends AbstractExecutorPool { /** * 线程池前缀名称:user-thread-pool-task- */ private final String threadNamePrefix = ThreadPoolConstants.USER_THREAD_PREFIX + ThreadPoolConstants.RUNNING_THREAD_SUFFIX; }
学校线程池
/** * 学校线程池参数类 */ @Component @ConfigurationProperties(prefix = "thread-pool.school-thread") @Data public class SchoolThreadPool extends AbstractExecutorPool { /** * 线程池前缀名称:school-thread-pool-task- */ private final String threadNamePrefix = ThreadPoolConstants.SCHOOL_THREAD_PREFIX + ThreadPoolConstants.RUNNING_THREAD_SUFFIX; }
3、创建线程池配置类
创建配置类 ThreadPoolConfig,负责创建线程池
ThreadPoolExecutor 类中提供的拒绝策略,也可以自定义策略。
(1)AbortPolicy 默认策略,队列满时抛出异常RejectedExecutionException
(2)DiscardOldestPolicy 去除队列中最早的任务,将新任务放入队列
(3)DiscardPolicy 直接丢掉任务
(4)CallerRunsPolicy 队列满时,主线程执行任务
(5)自定义处理策略
/** * 线程池配置类 */ @Configuration @EnableAsync @Slf4j public class ThreadPoolConfig { @Autowired private UserThreadPool userThreadPool; @Autowired private SchoolThreadPool schoolThreadPool; /** * 创建用户线程池 * beanName: "user-thread-exector-bean" */ @Bean(name = ThreadPoolConstants.USER_THREAD_PREFIX + ThreadPoolConstants.THREA_BEAN_SUFFIX) public ThreadPoolTaskExecutor userThreadExector() { return initExcutor(userThreadPool, userThreadPool.getThreadNamePrefix(), (r, executor) -> { log.info("userThreadExector队列已满,根据业务自行处理。。。"); }); } /** * 创建学校线程池 * beanName: "school-thread-exector-bean" */ @Bean(name = ThreadPoolConstants.SCHOOL_THREAD_PREFIX + ThreadPoolConstants.THREA_BEAN_SUFFIX) public ThreadPoolTaskExecutor schoolThreadExector() { return initExcutor(schoolThreadPool, schoolThreadPool.getThreadNamePrefix(),(r, executor) -> { log.info("schoolThreadExector队列已满,根据业务自行处理。。。"); }); } /** * 初始化线程池 * @param abstractExecutorPool * @param threadName * @param rejectedExecutionHandler * @return */ private ThreadPoolTaskExecutor initExcutor(AbstractExecutorPool abstractExecutorPool, String threadName, RejectedExecutionHandler rejectedExecutionHandler){ // 创建线程池并设置参数 ThreadPoolTaskExecutor threadPool = new ThreadPoolTaskExecutor(); threadPool.setCorePoolSize(abstractExecutorPool.getCorePoolSize()); threadPool.setMaxPoolSize(abstractExecutorPool.getMaxPoolSize()); threadPool.setKeepAliveSeconds(abstractExecutorPool.getKeepAliveSeconds()); threadPool.setQueueCapacity(abstractExecutorPool.getQueueCapacity()); threadPool.setThreadNamePrefix(threadName); threadPool.setRejectedExecutionHandler(rejectedExecutionHandler); return threadPool; } }
4、springboot启动类加上@EnableAsync
5、使用线程池
/** * 测试线程池service */ @Service public class TestThreadPoolService { @Autowired @Qualifier(ThreadPoolConstants.USER_THREAD_PREFIX + ThreadPoolConstants.THREA_BEAN_SUFFIX) private ThreadPoolTaskExecutor userTheadExector; @Autowired @Qualifier(ThreadPoolConstants.SCHOOL_THREAD_PREFIX + ThreadPoolConstants.THREA_BEAN_SUFFIX) private ThreadPoolTaskExecutor schoolThreadExector; /** * 测试线程 */ public void testUserThread(){ userTheadExector.execute(() ->{ try { // 设置睡眠时间让线程阻塞便于观察 Thread.sleep(5000); System.out.println(Thread.currentThread().getName() + "执行testUserThread业务完毕....................."); } catch (InterruptedException e) { e.printStackTrace(); } }); } /** * 测试线程 */ public void testSchoolThread(){ schoolThreadExector.execute(() ->{ try { // 设置睡眠时间让线程阻塞便于观察 Thread.sleep(3000); System.out.println(Thread.currentThread().getName() + "执行testSchoolThread业务完毕......................."); } catch (InterruptedException e) { e.printStackTrace(); } }); } public String getThreadPoolInfo() { return "user-thread-pool:"+ "corePoolSize:" + userTheadExector.getCorePoolSize() + "maxPoolSize:"+ userTheadExector.getMaxPoolSize() + "keepAliveSeconds:"+userTheadExector.getKeepAliveSeconds()+"\n" + "school-thread-pool:"+ "corePoolSize:" + schoolThreadExector.getCorePoolSize() + "maxPoolSize:"+ schoolThreadExector.getMaxPoolSize() + "keepAliveSeconds:"+schoolThreadExector.getKeepAliveSeconds(); } }
6、接口调用查看线程池执行情况
@RestController @RequestMapping("/thread") public class TestThreadPoolController { Logger logger = LoggerFactory.getLogger(this.getClass()); @Autowired TestThreadPoolService testThreadPoolService; @RequestMapping("/test") public String get(){ testThreadPoolService.testUserThread(); testThreadPoolService.testSchoolThread(); return "success"; } }
通过控制台查看打印信息
7、把线程池配置放到nacos,实现动态修改线程池的配置
nacos新建线程池专用的配置文件,注意推荐使用properties类型的配置文件,yaml类型的会读取不全配置信息的问题
8、spingboot项目中指定nacos配置的线程池配置文件
10、新增nacos配置文件修改监听器NacosListener,监听nacos配置的线程池配置文件的变化,监听到配置修改后重新设置到对应的业务线程池参数
/** * nacos配置中心监听器 */ @Component public class NacosListener implements ApplicationRunner { @Autowired NacosConfigManager nacosConfigManager; @Autowired NacosConfigProperties nacosConfigProperties; @Autowired ApplicationContext applicationContext; @Override public void run(ApplicationArguments args) throws Exception { //配置修改监听 nacosConfigManager.getConfigService().addListener("user-service-threadpool-config.properties", nacosConfigProperties.getGroup(), new PropertiesListener(){ @Override public void innerReceive(Properties properties) { System.out.println("nacos修改线程池配置,线程池重新设置!"); // 读取线程配置 Set<String> strings = properties.stringPropertyNames(); // 获取对应业务线程池 ThreadPoolTaskExecutor threadPoolTaskExecutor; for (String str : strings){ // 获取业务线程池bean对象 threadPoolTaskExecutor = (ThreadPoolTaskExecutor)applicationContext.getBean(str.substring(str.indexOf(".")+1, str.lastIndexOf(".")) + ThreadPoolConstants.THREAD_EXECTOR_BEAN_SUFFIX); // 核心线程数 if (str.contains(ThreadPoolConstants.THREAD_POOL_CORE_SIZE)){ threadPoolTaskExecutor.setCorePoolSize(Integer.parseInt(properties.getProperty(str))); } // 最大线程数 if (str.contains(ThreadPoolConstants.THREAD_POOL_MAX_SIZE)){ threadPoolTaskExecutor.setMaxPoolSize(Integer.parseInt(properties.getProperty(str))); } // 线程存活时长 if (str.contains(ThreadPoolConstants.THREAD_POOL_KEEP_ALIVE)){ threadPoolTaskExecutor.setKeepAliveSeconds(Integer.parseInt(properties.getProperty(str))); } // 队列长度 if (str.contains(ThreadPoolConstants.THREAD_POOL_QUEUE_CAPACITY)){ threadPoolTaskExecutor.setQueueCapacity(Integer.parseInt(properties.getProperty(str))); threadPoolTaskExecutor.initialize(); } } } }); } }
11、测试能否动态配置各业务线程池
我这里的配置user线程池配置最多只能执行4个任务,超过则提示,school线程池最多只能执行3个任务,超过则提示,我在页面调接口创建线程执行分别执行user线程池和school线程池,连续请求4次,预期结果应该是user线程池可以正常执行,school线程池则会提示
去nacos中修改一下线程池的配置,把user线程修改成最多只有2个任务执行,school线程最多只有4个任务执行
连续请求4次,预期结果和执行结果一致,代表动态修改线程池配置已经生效了
标签:ThreadPoolConstants,springboot,THREAD,thread,线程,动态,public,pool From: https://www.cnblogs.com/privateLogs/p/18413326