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