通过外置配置文件控制线程池

在应对大促压测时,为了适应多实例部署环境,需要根据实际情况动态调整线程池参数。本文介绍了通过外置配置文件(如阿里Diamond或Spring Cloud Config Server)来实现不重启应用即调整线程池的方法。文中详细讨论了核心线程数、最大线程池数、任务队列长度、超时时间及拒绝策略的修改,并指出了静态线程池对象直接更改可能带来的问题。为解决这个问题,提出了利用ThreadPoolExecutor的set方法结合定制方法调整任务队列长度,确保在修改配置时避免内存中存在两个线程池,从而防止双倍负荷和OOM风险。
摘要由CSDN通过智能技术生成

最近公司在搞大促压测,需要根据压测情况来配置线程池的参数。来达到最佳的效果。
由于一个机器现在是多实例部署的情况,所以理想化的线程数=cpu数*2的情况已经不适用了,需要根据压测的实际情况来调整。
所以写了一个通过外置配置文件(使用了阿里的diamond,当然也可以使用springCloud的config server)来达到不重启应用的情况下,动态的调整线程池的参数。
先贴上我的配置文件:一个非常简单的json字符串

{
   
  "coolPoolSize":"8",
  "maxPoolSize":"16",
  "maxWaitQueueSize":"1024",
  "keepAliveTime":"5",
  "rejectedHandler":"AbortPolicy"
}

对于动态修改线程池的问题
我这里只修改了 核心线程数,最大线程池数,任务队列长度,超时时间,拒绝策略这5个配置项。

然后对于修改线程池这块改动过一版。
原先是打算设置一个静态的线程池对象EXECTOR,然后当监听到配置文件发生变动,直接改变EXECTOR的指向
相关伪代码

        //指针指向新的线程池
        EXECUTOR = new ThreadPoolExecutor(
                corePoolSize
                ,maxPoolSize
                ,keepAliveTime
                ,TimeUnit.MILLISECONDS
                ,BLOCK_QUEUE
                ,FACTORY
                ,rejectedHandler);

但是这里存在一个隐患的点。如果采用了这套方案,若此时流量太大,我们去改变线程池的配置的时候,会在内存中生成两个线程池,另一个线程池得把任务执行完毕之后才会停止。双倍机器的负荷,容易产生隐患。

ThreadPoolExecutor其实已经提供了相关set方法,可以实时修改线程池的参数

        EXECUTOR.setCorePoolSize(corePoolSize);
        EXECUTOR.setMaximumPoolSize(maxPoolSize);
        EXECUTOR.setKeepAliveTime(keepAliveTime,TimeUnit.MILLISECONDS);
        EXECUTOR.setRejectedExecutionHandler(rejectedHandler);

但是却没有调整任务队列长度的能力,但是任务队列的长度也是需要考虑到的一个点,如果上来就是无界队列,是会存在oom的隐患的。

于是我又写了一点方法,提供了调整任务队列长度的能力
从这个角度出发,我们可以先关闭之前的线程池,然后把之前的任务搬到新的线程池中来执行。

相关方法

    //动态调整线程池参数
    private static void dynamicAdjustThreadPool(String content) {
   
        Map<String,String> config = null;
        try {
   
            config = (Map<String, String>) JSON.parse(content);
        } catch (Exception e) {
   
            log.error("parse to hashmap error  content = {} ",content,e);
            return;
        }
        //核心线程数
        Integer corePoolSize = getCorePoolSizeFromConfig(config);
        //最大线程数
        Integer maxPoolSize = getMaxPoolSizeFromConfig(config);
        //超时时间
        Integer keepAliveTime = getKeepAliveTimeFromConfig(config);
        //任务队列长度
        Integer maxWaitQueueSize = getMaxWaitQueueSizeFromConfig(config);
        //拒绝策略
        RejectedExecutionHandler rejectedHandler = getRejectedHandlerFromConfig(config);
        if (EXECUTOR==null){
   
            EXECUTOR = new ThreadPoolExecutor(
                    corePoolSize,
                    maxPoolSize,
                    keepAliveTime,
                    TimeUnit.MILLISECONDS,
                    new LinkedBlockingQueue<>(maxWaitQueueSize),
                    FACTORY,
                    rejectedHandler);
        }else {
   
            //队列容量发生变化的时候。需要重新new一个新的线程池,再把老的任务搬迁过去
            if (CURRENT_CAPACITY!=null && !CURRENT_CAPACITY.equals(maxWaitQueueSize)){
   
                adjustIfNewCapacity(corePoolSize, maxPoolSize, keepAliveTime, maxWaitQueueSize, rejectedHandler);
            }else {
   
                //当队列长度没变化时
                adjustIfOldCapacity(corePoolSize,maxPoolSize,keepAliveTime,rejectedHandler);
            }
        }
        //更新当前容量
        CURRENT_CAPACITY = maxWaitQueueSize;
    }

    /**
     * 当队列长度发生变化时
     * EXECUTOR指向新的线程池,并且把老的线程池中的任务搬迁过来
     */
    private static void adjustIfNewCapacity(Integer corePoolSize,
                                            Integer maxPoolSize,
                                            Integer keepAliveTime
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值