简易版美团动态线程池(配置中心动态配置参数)

1.前言

在高并发时代的今天,线程这个概念尤为重要,Java中创建一个线程的方式有很多,但是如今大部分公司都禁止手动创建线程来异步执行任务,而是必须使用线程池创建线程来执行任务,线程池可以帮助我们管理线程,与回收线程。大大降低消耗系统的资源与提高系统性能。

2.创建线程池

创建线程池的常见方法无非两种:

1.使用Executors工具类创建线程池,这个方法虽然方便但是缺点也很多,我实习的公司开发规范中命令禁止使用Executors工具类创建线程,至于为什么禁止使用我后续会发一篇详解线程池的文章其中就会提到这个问题

2.自己new ThreadPoolExecutor()使用其中的多个有参构造器可以很方便的帮助我们自定义创建线程池,每个参数都由我们自己配置,也可以帮助我们更了解我们创建的线程池性能指标。

3. 动态线程池

很早之前就听说美团开源了自己使用的动态线程池,前两天得空从GitHub上拉下来项目阅读了源码后,突发奇想写了一个简易版的动态线程池,虽然和美团开源的动态线程池没得比,但是还是很有学习意义的。

1.实现动态线程池的监控功能

这个功能的核心是使用动态代理,创建拒绝策略的动态代理对象,由于拒绝策略必须实现

RejectedExecutionHandler接口,所以我们可以直接使用JDK动态代理,使用Proxy.newInstance()方法创建拒绝策略的代理对象

 要实现代理类,就需要我们写一个类实现InvocationHandler接口,其中来写我们的增强方法,即在代理类中在target对象执行方法前执行的代码,这里我就只实现了记录被拒绝次数,其实还可以监控很多数据。

 2.对外提供构建线程池的类,在这个类中我们提供了几个静态方法供外界创建线程,创建了全局的Map变量用于存储所有通过这个类创建的线程池,为后续使用配置中心刷新线程池配置做准备。

当时写代码的时候我想到既然这个类中都存储了所有构建的线程池,那在这个类中用来实时监控线程池参数也就不需要之前的代理类了。所以我创建了一个定时线程池,定时去遍历存储所有线程池的Map集合,监控线程池中的任务使用情况,以及非核心线程池使用情况

 这个RefrashThreadPoolConfig方法就是使用已经解析过的从配置中心发送来的新配置,来配置线程池

 3.使用Nacos配置中心来动态配置线程池

1.项目导入Nacos-config依赖,注意依赖版本要和Springboot版本对应

 创建bootStrap.yml编写配置

我打红线的配置都是很重要的配置,必须要配置,否则无法正确从配置中心读取配置,至于profiles.active这个配置不配置也无所谓,只要在nacos配置中心编写配置文件的时候中间不用加dev即可 

在nacos中编写配置文件即可,这里不做过多赘述

最最最重要的一步来了 ,在项目中配置nacos配置监听器

这里使用了InitialzingBean接口,即spring提供的bean初始化回调接口,在spring初始化完成这个bean后,如果我们的组件实现了这个接口spring就会回调afterPropertisSet()这个方法来对我们的bean做增强

逻辑也很简单,大家自己看代码即可,我们在nacos动态刷新配置后,回调接口

@Component
public class DynamicThreadPoolRefresher implements InitializingBean {
    //实现InitializingBean接口在初始化类后会回调afterPropertis方法来增强bean
    @Resource
    private NacosConfigManager nacosConfigManager;
    @Override
    public void afterPropertiesSet() throws Exception {
        nacosConfigManager.getConfigService().addListener("threadpool-dev.properties", "DEFAULT_GROUP", new Listener() {
            @Override
            public Executor getExecutor() {
                //返回一个线程池
                return Executors.newSingleThreadExecutor();
            }

            @Override
            public void receiveConfigInfo(String s) {
                refreshConfig(s);
            }
        });
    }

    private void refreshConfig(String config) {
        Properties threadProperties = new Properties();
        try {
            threadProperties.load(new StringReader(config));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        Set<Object> configSet = threadProperties.keySet();
        Map<String,Integer> configMap = new HashMap<>();
        for (Object o : configSet) {
            String configString = o.toString();
            String[] configNums = configString.split("\\.");
            //线程池名字
            String threadPoolName = configNums[2];
            //配置参数类型
            String configType = configNums[3];
            //将线程池名字与参数类型作为key,可以防止配置到其他线程池中去
            String configKey = threadPoolName+configType;
            String configPropertiesValue = threadProperties.getProperty(o.toString());
            configMap.put(configKey, Integer.valueOf(configPropertiesValue));
            System.out.println("修改线程池参数:" + configKey + "为" + configPropertiesValue);
        }
        DynamicThreadRegister.refreshThreadPoolConfig(configMap);
    }
}

 效果演示:

这里我写了一个测试类,实现ApplicationRunner接口,可以帮助我们进行效果演示 

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,以下是一个简易的动态页面的HTML、CSS和JS代码示例: HTML代码: ``` <!DOCTYPE html> <html> <head> <title>动态页面</title> <link rel="stylesheet" type="text/css" href="style.css"> </head> <body> <div id="container"> <h1>动态页面示例</h1> <p id="time"></p> <button id="btn">点击我更新时间</button> </div> <script src="script.js"></script> </body> </html> ``` CSS代码: ``` #container { margin: 0 auto; text-align: center; } #time { font-size: 24px; margin-bottom: 20px; } button { font-size: 20px; padding: 10px 20px; border-radius: 5px; background-color: #008CBA; color: #fff; border: none; cursor: pointer; } button:hover { background-color: #006B9F; } ``` JS代码: ``` window.onload = function() { var timeEl = document.getElementById("time"); var btnEl = document.getElementById("btn"); function updateTime() { var currentTime = new Date(); var hours = currentTime.getHours(); var minutes = currentTime.getMinutes(); var seconds = currentTime.getSeconds(); //加0操作 if (hours < 10) { hours = "0" + hours; } if (minutes < 10) { minutes = "0" + minutes; } if (seconds < 10) { seconds = "0" + seconds; } var timeString = hours + ":" + minutes + ":" + seconds; timeEl.innerHTML = timeString; } btnEl.onclick = function() { updateTime(); } updateTime(); setInterval(updateTime, 1000); } ``` 以上代码实现了一个带有动态时间更新效果的页面。当用户点击“点击我更新时间”按钮时,页面上的时间会更新。同时,页面上还包含了一些基本的CSS样式,使页面看起来更加美观。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LinkJii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值