古之立大事者,不惟有超世之才,亦必有坚忍不拔之志
个人CSND主页——Micro麦可乐的博客
《Docker实操教程》专栏以最新的Centos版本为基础进行Docker实操教程,入门到实战
《RabbitMQ》专栏19年编写主要介绍使用JAVA开发RabbitMQ的系列教程,从基础知识到项目实战
《设计模式》专栏以实际的生活场景为案例进行讲解,让大家对设计模式有一个更清晰的理解
《开源项目》本专栏主要介绍目前热门的开源项目,带大家快速了解并轻松上手使用
✨《开发技巧》本专栏包含了各种系统的设计原理以及注意事项,并分享一些日常开发的功能小技巧
《Jenkins实战》专栏主要介绍Jenkins+Docker的实战教程,让你快速掌握项目CI/CD,是2024年最新的实战教程
《Spring Boot》专栏主要介绍我们日常工作项目中经常应用到的功能以及技巧,代码样例完整
《Spring Security》专栏中我们将逐步深入Spring Security的各个技术细节,带你从入门到精通,全面掌握这一安全技术
如果文章能够给大家带来一定的帮助!欢迎关注、评论互动~
在分布式系统架构中,线程池是资源调度的重要工具。传统固定参数的线程池在流量平稳的场景下表现良好,但面对现代互联网业务的潮汐流量特征时,往往会出现资源浪费或处理能力不足
的问题。
例如 电商促销活动期间访问量激增,正常时段则近乎空闲。固定线程池若过大,会在空闲期造成大量线程资源浪费;若过小,则在高峰期不能及时响应请求,导致排队或超时失败。为此,为了保证高峰期的吞吐量与低谷期的资源利用率,我们需要一个能够在运行时根据业务负载自动扩容和收缩的线程池。
借助 Nacos
配置中心,我们可以将线程池的核心参数(如核心线程数、最大线程数、队列容量、空闲回收时间等)下发到客户端,并通过配置刷新实现热更新,无需重启应用即可生效
CPU
切换开销;Executors.newFixedThreadPool(n)
在任何时刻都维护 n 条线程,无法自动回收空闲线程;自动扩容:当任务提交速率超过核心线程数且队列已满时,线程池会继续创建新线程,直到达到最大线程数
自动收缩:通过调用 allowCoreThreadTimeOut(true)
,使得核心线程在空闲超过 keepAliveTime
后也能被回收;
项目中引入 Spring Cloud Alibaba Nacos 依赖:
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>spring-cloud-starter-alibaba-nacos-configartifactId>
<version>2023.0.1.0version>
dependency>
在 application.yml
中配置 Nacos
服务器地址与应用名:
spring:
application:
name: dynamic-threadpool-demo
cloud:
nacos:
config:
server-addr: 127.0.0.1:8848
file-extension: yaml
refresh-enabled: true
在 Nacos
控制台创建 Data ID:dynamic-threadpool-demo.yaml
,内容示例:
threadpool:
coreSize: 5
maxSize: 20
queueCapacity: 100
keepAliveSeconds: 60
该文件存储线程池的各项参数,后续可在控制台直接修改并实时下发应用实例
定义线程池配置类,并使用 @ConfigurationProperties
读取 Nacos
配置:
@Component
@RefreshScope
@ConfigurationProperties(prefix = "threadpool")
public class ThreadPoolProperties {
private int coreSize;
private int maxSize;
private int queueCapacity;
private long keepAliveSeconds;
// getters & setters
}
在工厂类中注入 ThreadPoolProperties
,并在配置变更时重建或调整现有线程池实例:
@Component
public class DynamicThreadPoolManager {
private volatile ThreadPoolExecutor executor;
private final ThreadPoolProperties props;
public DynamicThreadPoolManager(ThreadPoolProperties props) {
this.props = props;
this.executor = createExecutor(props);
}
@NacosConfigListener(dataId = "${spring.application.name}.yaml", timeout = 5000)
public void onChange(String newContent) throws JsonProcessingException {
ThreadPoolProperties updated = new ObjectMapper()
.readValue(newContent, ThreadPoolProperties.class);
executor.setCorePoolSize(updated.getCoreSize());
executor.setMaximumPoolSize(updated.getMaxSize());
executor.setKeepAliveTime(updated.getKeepAliveSeconds(), TimeUnit.SECONDS);
// 如果需要修改队列容量,则重建 executor
}
private ThreadPoolExecutor createExecutor(ThreadPoolProperties p) {
return new ThreadPoolExecutor(
p.getCoreSize(), p.getMaxSize(),
p.getKeepAliveSeconds(), TimeUnit.SECONDS,
new LinkedBlockingQueue<>(p.getQueueCapacity()),
r -> new Thread(r, "dyn-pool-" + UUID.randomUUID()),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
public void submit(Runnable task) {
executor.execute(task);
}
}
启动测试,调用 CommandLineRunner
实现项目启动后执行一些初始化操作。代码如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner demo(DynamicThreadPoolManager manager) {
return args -> {
for (int i = 0; i < 50; i++) {
int id = i;
manager.submit(() -> {
System.out.println(Thread.currentThread().getName() + " - Task " + id);
});
}
};
}
}
Nacos Server
与该示例项目,观察日志中线程池参数初始化信息Nacos
中的参数(如 coreSize
、maxSize
),点击刷新,应用将自动触发回调并调整线程池设置,无需重启executor.getPoolSize()
、getActiveCount()
、getQueue().size()
等指标进行实时监控与对比验证通过将 Nacos
配置中心与 ThreadPoolExecutor
结合,我们成功实现了线程池参数的热更新与动态调整,满足了高并发场景下的自动扩缩容需求。实践中还进一步延展到更多场景,如 消息队列消费者、异步任务执行等,为微服务系统带来更高的灵活性与可运营性。
如果你在实践过程中有任何疑问或更好的扩展思路,欢迎在评论区留言,最后希望大家 一键三连 给博主一点点鼓励!