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
浙公网安备 33010602011771号