ThreadPoolExecutor---动态线程池+监控

 

背景

  

实现

  nacos + springboot

nacos

  https://nacos.io/zh-cn/docs/quick-start.html

  下载解压

    unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz cd nacos/bin

  启动

    sh startup.sh -m standalone

  控制台

    http://127.0.0.1:8848

工程结构  

  由2个模块组成,dtp单独作为动态线程池模块,test为测试模块(依赖dtp)

  

父pom

  

dtp模块

  

  pom

<dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

        <!--        nacos consumer-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.7</version>
        </dependency>

    </dependencies>

  自定义线程池

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author apy
 * @description
 * @date 2023/8/11 11:21
 */
public class DtpExecutor extends ThreadPoolExecutor {

    public DtpExecutor(int corePoolSize, int maximumPoolSize) {
        super(corePoolSize, maximumPoolSize, 100, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(100));
    }
}

  

  nacos配置

    

dtp:
  executors:
    - name: t1
      core-pool-size: 15
      max-pool-size: 20
    - name: t2
      core-pool-size: 12
      max-pool-size: 20

  nacos配置对应的多线程池class 

import org.springframework.boot.context.properties.ConfigurationProperties;
import java.util.List;

@ConfigurationProperties(prefix = "dtp") // 与nacos的配置文件dtp.yml进行绑定
public class DtpProperties {

    private List<DtpExecutorProperties> executors;

    public static class DtpExecutorProperties{
        private String name;
        private Integer corePoolSize = 10;
        private Integer maxPoolSize = 10;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Integer getCorePoolSize() {
            return corePoolSize;
        }

        public void setCorePoolSize(Integer corePoolSize) {
            this.corePoolSize = corePoolSize;
        }

        public Integer getMaxPoolSize() {
            return maxPoolSize;
        }

        public void setMaxPoolSize(Integer maxPoolSize) {
            this.maxPoolSize = maxPoolSize;
        }
    }

    public List<DtpExecutorProperties> getExecutors() {
        return executors;
    }

    public void setExecutors(List<DtpExecutorProperties> executors) {
        this.executors = executors;
    }
}



import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author apy
 * @description
 * @date 2023/8/11 14:50
 */
public class DtpImportBeanDefinitionRegister implements ImportBeanDefinitionRegistrar, EnvironmentAware {

    private Environment environment;

    public void setEnvironment(Environment environment) {
        this.environment = environment;
    }

    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {

        // 从当前spring容器environment中读取DtpProperties
        DtpProperties dtpProperties = new DtpProperties();

        Binder binder = Binder.get(environment);
        ResolvableType resolvableType = ResolvableType.forClass(DtpProperties.class);
        Bindable<Object> target = Bindable.of(resolvableType).withExistingValue(dtpProperties);
        binder.bind("dtp", target);

        // 遍历DtpProperties,注册BeanDefinition
        for (DtpProperties.DtpExecutorProperties executorProperties : dtpProperties.getExecutors()){

            AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
            beanDefinition.setBeanClass(DtpExecutor.class);
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(executorProperties.getCorePoolSize());
            beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(executorProperties.getMaxPoolSize());

            registry.registerBeanDefinition(executorProperties.getName(), beanDefinition);
        }
    }
}

  线程池工具类

public class DtpUtil {

    public static Map<String, DtpExecutor> map = new HashMap<String, DtpExecutor>();

    public static void setMap(String name, DtpExecutor dtpExecutor) {
        map.put(name, dtpExecutor);
    }

    public static DtpExecutor get(String name){
        return map.get(name);
    }
}


public class DtpBeanPostProcessor implements BeanPostProcessor {

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof DtpExecutor){
            DtpUtil.setMap(beanName, (DtpExecutor) bean);
        }
        return bean;
    }
}

  

  nacos监听器

import com.alibaba.nacos.api.annotation.NacosInjected;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.context.properties.bind.Bindable;
import org.springframework.boot.context.properties.bind.Binder;
import org.springframework.boot.context.properties.source.ConfigurationPropertySource;
import org.springframework.boot.context.properties.source.MapConfigurationPropertySource;
import org.springframework.core.ResolvableType;
import org.springframework.core.io.ByteArrayResource;
import java.util.Properties;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

/**
 * @author apy
 * @description
 * @date 2023/8/11 12:01
 */
public class NacosDtpListener implements Listener, InitializingBean {

    @NacosInjected
    private ConfigService configService;

    public Executor getExecutor() {
        return Executors.newSingleThreadExecutor();
    }

    /**
     * 当nacos指定配置文件发生变化时,调用this.getExecutor()获得线程池,触发receiveConfigInfo执行
     * @param config
     */
    public void receiveConfigInfo(String config) {
        // 读取nacos的dtp.yml
        YamlPropertiesFactoryBean bean = new YamlPropertiesFactoryBean();
        bean.setResources(new ByteArrayResource(config.getBytes()));
        Properties properties = bean.getObject();

        // 将nacos配置转换为DtpProperties
        DtpProperties dtpProperties = new DtpProperties();
        ConfigurationPropertySource sources = new MapConfigurationPropertySource(properties);
        Binder binder = new Binder(sources);
        ResolvableType resolvableType = ResolvableType.forClass(DtpProperties.class);
        Bindable<Object> target = Bindable.of(resolvableType).withExistingValue(dtpProperties);
        binder.bind("dtp", target);

        // 遍历DtpProperties获取对应的DtpExecutor,更新参数
        for (DtpProperties.DtpExecutorProperties executorProperties : dtpProperties.getExecutors()){
            DtpExecutor dtpExecutor = DtpUtil.get(executorProperties.getName());
            dtpExecutor.setCorePoolSize(executorProperties.getCorePoolSize());
            dtpExecutor.setMaximumPoolSize(executorProperties.getMaxPoolSize());
        }
    }

    /**
     * spring容器启动时,将NacosDtpListener 与 nacos配置文件dtp.yml进行绑定
     * @throws Exception
     */
    public void afterPropertiesSet() throws Exception {
        configService.addListener("dtp.yml", "DEFAULT_GROUP", this);
    }
}

  动态线程池监视器(由一个定时任务线程,定时去监控线程池变化)

import org.springframework.beans.factory.InitializingBean;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author apy
 * @description
 * @date 2023/8/11 15:40
 */
public class DtpMonitor implements InitializingBean {

    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1);

    public void afterPropertiesSet() throws Exception {
        executorService.scheduleAtFixedRate(() -> {

            for (Map.Entry<String, DtpExecutor> dtpExecutorEntry : DtpUtil.map.entrySet()) {
                String executorName = dtpExecutorEntry.getKey();
                DtpExecutor dtpExecutor = dtpExecutorEntry.getValue();

                int activeCount = dtpExecutor.getActiveCount();
                if (activeCount > 2){
                    System.out.println(String.format("%s线程池活跃线程数是:%s", executorName, activeCount));
                }

            }
        }, 5, 5, TimeUnit.SECONDS);
    }
}

  dtp配置类

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

/**
 * @author apy
 * @description
 * @date 2023/8/11 11:42
 */
@Configuration
@EnableConfigurationProperties(value = DtpProperties.class)
@Import(value = {DtpImportBeanDefinitionRegister.class, DtpBeanPostProcessor.class})
public class DtpConfig {

    @Bean
    public NacosDtpListener nacosDtpListener(){
        return new NacosDtpListener();
    }

    @Bean
    public DtpMonitor dtpMonitor(){
        return new DtpMonitor();
    }

}

  

test模块

  

 

  pom

<dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.2.2.RELEASE</version>
        </dependency>

<!--        nacos consumer-->
        <dependency>
            <groupId>com.alibaba.boot</groupId>
            <artifactId>nacos-config-spring-boot-starter</artifactId>
            <version>0.2.7</version>
        </dependency>

        <dependency>
            <groupId>org.example</groupId>
            <artifactId>dtp</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

  controller

@RestController
public class Controller {

    @GetMapping(value = "/test1")
    public Integer test1(){
        DtpExecutor t1 = DtpUtil.get("t1");
        t1.execute(() -> doTask());
        return t1.getCorePoolSize();
    }

    @GetMapping(value = "/test2")
    public Integer test2(){
        DtpExecutor t2 = DtpUtil.get("t2");
        t2.execute(() -> doTask());
        return t2.getCorePoolSize();
    }

    private void doTask(){
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

  starter

@SpringBootApplication
public class Starter {
    public static void main(String[] args) {
        SpringApplication.run(Starter.class, args);
    }
}

  application.yml

nacos:
  config:
    service-addr: 127.0.0.1:8848
    data-id: dtp.yml
    type: yaml
    auto-refresh: true
    bootstrap:
      enable: true

  

 

  

  

  

 

 

  

 

  

 

posted on 2023-07-26 17:00  anpeiyong  阅读(230)  评论(0编辑  收藏  举报

导航