首页 > 其他分享 >springboot动态线程池

springboot动态线程池

时间:2024-09-14 09:24:13浏览次数:10  
标签:ThreadPoolConstants springboot THREAD thread 线程 动态 public pool

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

相关文章

  • vue3/provider 和 inject实现跨组件动态数据传递。
    实现跨层传递在Vue中,provider和inject是一种用于实现依赖注入的高级特性,允许一个祖先组件向其所有子孙组件注入一个依赖,而不论组件层次有多深,并在起上下游关系成立的时间里始终生效。这在某些场景下非常有用,比如当你需要跨多个组件层级传递数据时。定义provide对象:在父组......
  • 基于SpringBoot+Vue+uniapp的小码创客教育教学资源库(源码+lw+部署文档+讲解等)
    文章目录前言详细视频演示具体实现截图技术栈后端框架SpringBoot前端框架Vue持久层框架MyBaitsPlus系统测试系统测试目的系统功能测试系统测试结论为什么选择我代码参考数据库参考源码获取前言......
  • 将springboot项目打成war包
    1.将启动项打包程序修改为war包 <packaging>war</packaging>2.去除原有的jar包打包插件,换位war包打包插件本插件支持springboot2.7.12jdk1.8,需要项目的版本选择合适的打包版 基本到这里war包已经打包成功,我们可以放到tomcat试一下 ,有乱码,试试请求一下,可以成功 ......
  • 基于Java+Springboot+Vue开发的在线摄影预约管理系统
    项目简介该项目是基于Java+Springboot+Vue开发的在线摄影预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的在线摄影管理系统项目,大学生可以在实践中学习和提......
  • 基于Java+Springboot+Vue开发的母婴商城管理系统
    项目简介该项目是基于Java+Springboot+Vue开发的母婴商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的网上母婴商城管理系统项目,大学生可以在实践中学习和提......
  • 基于Java+Springboot+Vue开发的农产品商城管理系统
    项目简介该项目是基于Java+Springboot+Vue开发的农产品商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的农产品商城管理系统项目,大学生可以在实践中学习和......
  • 基于Java+Springboot+Vue开发的新闻管理系统
    项目简介该项目是基于Java+Springboot+Vue开发的新闻管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的新闻管理系统项目,大学生可以在实践中学习和提升自己的能力......
  • 基于Java+Springboot+Vue开发的音乐推荐管理系统
    项目简介该项目是基于Java+Springboot+Vue开发的音乐推荐管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的音乐推荐管理系统项目,大学生可以在实践中学习和提升自......
  • 【开题报告】基于Springboot+vue居民社区报修系统设计与实现(程序+源码+论文) 计算机毕
    本系统(程序+源码)带文档lw万字以上文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着城市化进程的加速和居民生活品质的提升,社区作为城市生活的基本单元,其管理服务水平直接关系到居民的生活质量。在传统的社区报修模式中,居民往往通......
  • C#笔记13 线程同步概念及其实现,详解lock,Monitor,Mutex代码用法
    同步的概念在我们学会在C#中使用线程之后,我们拥有了把一个程序中的不同代码段在不同线程中运行的能力,可以说此时我们已经能够做到让他们分别执行,异步执行。对于我们的桌面端程序,使用多线程可以让我们在后台进行操作的时候保持用户界面的响应。对于服务器应用程序,多线程可以......