Java中线程池是管理多线程任务的工具。标准的ThreadPoolExecutor
允许我们设置核心线程数、最大线程数、队列容量等参数,但这些参数在初始化后无法动态调整。有时候,可能需要根据系统负载动态调整线程池参数,以优化性能。
在某些场景下,线程池的负载可能会随时间变化。例如:
标准的ThreadPoolExecutor
无法在运行时动态调整核心线程数、最大线程数等参数,因此需要实现一个动态线程池。
Java动态改变线程池核心参数的原理主要依赖于ThreadPoolExecutor
类本身提供的灵活性。ThreadPoolExecutor
是Java标准库中用于管理线程池的核心类,它允许在运行时动态调整一些关键参数,如核心线程数、最大线程数、线程空闲时间等。
ThreadPoolExecutor
的核心参数keepAliveTime
后会被回收。这些参数在ThreadPoolExecutor
初始化时设置,但部分参数可以在运行时动态修改。
ThreadPoolExecutor
提供了以下方法,允许在运行时动态调整核心参数:
setCorePoolSize(int corePoolSize)
corePoolSize
大于当前的核心线程数,线程池会创建新的线程,直到线程数达到新的corePoolSize
。corePoolSize
小于当前的核心线程数,多余的线程会在空闲时被回收(根据keepAliveTime
)。corePoolSize
,线程池会立即创建新线程来处理任务。setMaximumPoolSize(int maximumPoolSize)
maximumPoolSize
小于当前的最大线程数,多余的线程会在空闲时被回收。maximumPoolSize
大于当前的最大线程数,且任务队列已满,线程池会创建新线程来处理任务。setKeepAliveTime(long time, TimeUnit unit)
keepAliveTime
后会被回收。allowCoreThreadTimeOut(boolean value)
true
,核心线程在空闲时间超过keepAliveTime
后也会被回收。false
,核心线程会一直存活,即使处于空闲状态。ThreadPoolExecutor
的内部实现基于一个AtomicInteger
类型的变量ctl
,它同时存储了线程池的状态(如运行中、关闭等)和当前线程数。动态调整参数时,ThreadPoolExecutor
会通过以下步骤实现:
参数验证:
setCorePoolSize
或setMaximumPoolSize
时,会验证新参数是否合法(如corePoolSize
不能大于maximumPoolSize
)。线程创建或回收:
corePoolSize
大于当前线程数,线程池会调用addWorker
方法创建新线程。corePoolSize
小于当前线程数,多余的线程会在空闲时被回收。任务处理:
corePoolSize
,线程池会立即创建新线程来处理任务。状态更新:
corePoolSize
、maximumPoolSize
等),并通知相关组件(如任务队列、线程工厂等)。动态调整线程池核心参数:
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.LinkedBlockingQueue;
public class DynamicThreadPoolExecutor extends ThreadPoolExecutor {
public DynamicThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
// 动态设置核心线程数
public void setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0 || corePoolSize > getMaximumPoolSize()) {
throw new IllegalArgumentException(".........");
}
super.setCorePoolSize(corePoolSize);
}
// 动态设置最大线程数
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize < 1 || maximumPoolSize < getCorePoolSize()) {
throw new IllegalArgumentException(".....");
}
super.setMaximumPoolSize(maximumPoolSize);
}
// 动态设置线程空闲时间
public void setKeepAliveTime(long time, TimeUnit unit) {
super.setKeepAliveTime(time, unit);
}
public static void main(String[] args) {
DynamicThreadPoolExecutor executor = new DynamicThreadPoolExecutor(
2, // 初始核心线程数
4, // 初始最大线程数
60, // 线程空闲时间
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10)
);
// 提交任务
for (int i = 0; i < 10; i++) {
executor.execute(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Task executed by " + Thread.currentThread().getName());
});
}
// 动态调整线程池参数
executor.setCorePoolSize(4);
executor.setMaximumPoolSize(8);
executor.setKeepAliveTime(30, TimeUnit.SECONDS);
// 关闭线程池
executor.shutdown();
}
}
Nacos控制台中创建配置文件,内容:
threadpool:
corePoolSize: 2
maxPoolSize: 4
queueCapacity: 10
keepAliveSeconds: 60
创建配置类,用于从Nacos中读取线程池配置,并动态调整线程池参数。
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "threadpool")
@RefreshScope // 支持动态刷新
public class ThreadPoolProperties {
private int corePoolSize;
private int maxPoolSize;
private int queueCapacity;
private int keepAliveSeconds;
public int getCorePoolSize() {
return corePoolSize;
}
public void setCorePoolSize(int corePoolSize) {
this.corePoolSize = corePoolSize;
}
public int getMaxPoolSize() {
return maxPoolSize;
}
public void setMaxPoolSize(int maxPoolSize) {
this.maxPoolSize = maxPoolSize;
}
public int getQueueCapacity() {
return queueCapacity;
}
public void setQueueCapacity(int queueCapacity) {
this.queueCapacity = queueCapacity;
}
public int getKeepAliveSeconds() {
return keepAliveSeconds;
}
public void setKeepAliveSeconds(int keepAliveSeconds) {
this.keepAliveSeconds = keepAliveSeconds;
}
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@Configuration
public class ThreadPoolConfig {
@Autowired
private ThreadPoolProperties threadPoolProperties;
@Bean
@RefreshScope // 支持动态刷新
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
executor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
executor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
executor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
executor.setThreadNamePrefix("DynamicThreadPool-");
executor.initialize();
return executor;
}
}
通过监听Nacos配置变化,动态调整线程池参数。监听配置刷新事件:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.cloud.context.scope.refresh.RefreshScopeRefreshedEvent;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
@Component
@RefreshScope
public class ThreadPoolRefresher {
@Autowired
private ThreadPoolTaskExecutor threadPoolTaskExecutor;
@Autowired
private ThreadPoolProperties threadPoolProperties;
@EventListener
public void onRefreshScopeRefreshed(RefreshScopeRefreshedEvent event) {
// 动态调整线程池参数
threadPoolTaskExecutor.setCorePoolSize(threadPoolProperties.getCorePoolSize());
threadPoolTaskExecutor.setMaxPoolSize(threadPoolProperties.getMaxPoolSize());
threadPoolTaskExecutor.setQueueCapacity(threadPoolProperties.getQueueCapacity());
threadPoolTaskExecutor.setKeepAliveSeconds(threadPoolProperties.getKeepAliveSeconds());
System.out.println("Thread pool parameters refreshed!");
System.out.println("Core Pool Size: " + threadPoolTaskExecutor.getCorePoolSize());
System.out.println("Max Pool Size: " + threadPoolTaskExecutor.getMaxPoolSize());
System.out.println("Queue Capacity: " + threadPoolTaskExecutor.getQueueCapacity());
System.out.println("Keep Alive Seconds: " + threadPoolTaskExecutor.getKeepAliveSeconds());
}
}
Spring Cloud中,RefreshScopeRefreshedEvent 是一个事件类,用于表示 @RefreshScope 注解的Bean被刷新的事件。当配置中心(如Nacos)中的配置发生变化时,Spring Cloud会触发这个事件,通知所有标记为 @RefreshScope 的Bean重新加载配置。
RefreshScopeRefreshedEvent 的作用:
动态刷新配置:当Nacos中的配置发生变化时,Spring Cloud会发布 RefreshScopeRefreshedEvent 事件。
重新初始化Bean:所有标记为 @RefreshScope 的Bean会重新初始化,加载最新的配置值。
自定义逻辑:可以通过监听 RefreshScopeRefreshedEvent 事件,在配置刷新时执行自定义逻辑(如动态调整线程池参数)
在Nacos控制台中修改threadpool.corePoolSize
、threadpool.maxPoolSize
等参数:
threadpool:
corePoolSize: 4
maxPoolSize: 8
queueCapacity: 20
keepAliveSeconds: 30
当Nacos配置发生变化时,Spring Boot会自动刷新 @RefreshScope
的Bean,并触发 RefreshScopeRefreshedEvent
事件。日志中会输出:
Thread pool parameters refreshed!
Core Pool Size: 4
Max Pool Size: 8
Queue Capacity: 20
Keep Alive Seconds: 30
通过结合Spring Boot和Nacos配置中心,可以实现线程池参数的动态调整。关键点包括:
@RefreshScope
注解支持配置的动态刷新。ThreadPoolTaskExecutor
动态调整线程池参数。RefreshScopeRefreshedEvent
事件,实时更新线程池配置。