Java线程池是应用服务器处理并发请求的核心组件,参数配置不当直接导致OOM、响应超时或资源浪费。从ThreadPoolExecutor的核心参数到Spring Boot中的线程池隔离,从动态调整到拒绝策略选择,线程池的调优需要结合具体业务场景精细化配置。
ThreadPoolExecutor核心参数详解
import java.util.concurrent.*;
// ThreadPoolExecutor的七个核心参数
ThreadPoolExecutor executor = new ThreadPoolExecutor(
10, // corePoolSize: 核心线程数
50, // maximumPoolSize: 最大线程数
60L, // keepAliveTime: 空闲线程存活时间
TimeUnit.SECONDS, // 时间单位
new LinkedBlockingQueue<>(1000), // workQueue: 任务队列
new ThreadFactory() { // threadFactory: 线程工厂
private final AtomicInteger counter = new AtomicInteger(0);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "biz-pool-" + counter.incrementAndGet());
t.setDaemon(false);
t.setUncaughtExceptionHandler((thread, ex) -> {
log.error("Thread {} exception", thread.getName(), ex);
});
return t;
}
},
new ThreadPoolExecutor.CallerRunsPolicy() // handler: 拒绝策略
);
// 参数含义详解:
// 1. 请求到达时,先判断核心线程是否已满
// 2. 未满则创建新线程执行
// 3. 已满则将任务加入队列
// 4. 队列已满则判断是否超过最大线程数
// 5. 未超过则创建非核心线程
// 6. 超过则执行拒绝策略
拒绝策略对比与选择
// 四种内置拒绝策略
// 1. AbortPolicy(默认):抛出RejectedExecutionException
// 适用:对丢弃任务敏感的场景
new ThreadPoolExecutor.CallerRunsPolicy()
// 2. CallerRunsPolicy:由提交线程执行任务
// 适用:IO密集型任务,可起到背压限流作用
new ThreadPoolExecutor.CallerRunsPolicy()
// 3. DiscardPolicy:静默丢弃新任务
// 不推荐:无告知,难以发现任务丢失
new ThreadPoolExecutor.DiscardPolicy()
// 4. DiscardOldestPolicy:丢弃队列最旧任务
// 适用:实时性要求高的场景
new ThreadPoolExecutor.DiscardOldestPolicy()
// 自定义拒绝策略:记录拒绝日志 + 上报
public class LoggingRejectedHandler implements RejectedExecutionHandler {
private final MeterRegistry meterRegistry;
public LoggingRejectedHandler(MeterRegistry meterRegistry) {
this.meterRegistry = meterRegistry;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
Counter.builder("thread.pool.rejected")
.tag("pool", executor.toString())
.register(meterRegistry)
.increment();
log.warn("Task rejected, pool={}, queue={}",
executor.getActiveCount(),
executor.getQueue().size());
throw new RejectedExecutionException(
"Thread pool " + executor + " is saturated");
}
}
Spring Boot线程池隔离与配置
// 配置类
@Configuration
public class ThreadPoolConfig {
@Bean("orderExecutor")
public ThreadPoolExecutor orderExecutor() {
return new ThreadPoolExecutor(
20, 50, 60, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(500),
new ThreadFactory() {
private final AtomicInteger n = new AtomicInteger(0);
public Thread newThread(Runnable r) {
return new Thread(r, "order-pool-" + n.incrementAndGet());
}
},
new LoggingRejectedHandler(meterRegistry)
);
}
@Bean("emailExecutor")
public ThreadPoolExecutor emailExecutor() {
// 邮件发送:CPU密集型,核心线程设为CPU核数
return new ThreadPoolExecutor(
Runtime.getRuntime().availableProcessors(),
Runtime.getRuntime().availableProcessors() * 2,
30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(2000),
new ThreadPoolExecutor.CallerRunsPolicy()
);
}
}
// 使用@Async注解指定线程池
@Service
public class OrderService {
@Async("orderExecutor")
public CompletableFuture<OrderResult> processOrder(Order order) {
// 业务逻辑
return CompletableFuture.completedFuture(result);
}
}
// 启用@Async
@EnableAsync
@SpringBootApplication
public class Application { }
动态调整线程池参数
// 运行时动态调整线程池参数
@Component
public class ThreadPoolManager {
private final Map<String, ThreadPoolExecutor> pools = new ConcurrentHashMap<>();
public void register(String name, ThreadPoolExecutor pool) {
pools.put(name, pool);
}
// 动态调整核心线程数
public void resize(String name, int coreSize, int maxSize) {
ThreadPoolExecutor pool = pools.get(name);
if (pool == null) return;
pool.setCorePoolSize(coreSize);
pool.setMaximumPoolSize(maxSize);
log.info("Resized pool {}: core={}, max={}", name, coreSize, maxSize);
}
// 获取线程池监控指标
public Map<String, Object> getStats(String name) {
ThreadPoolExecutor pool = pools.get(name);
Map<String, Object> stats = new HashMap<>();
stats.put("activeCount", pool.getActiveCount());
stats.put("poolSize", pool.getPoolSize());
stats.put("queueSize", pool.getQueue().size());
stats.put("completedTaskCount", pool.getCompletedTaskCount());
stats.put("largestPoolSize", pool.getLargestPoolSize());
return stats;
}
}
// 结合Apollo或Nacos配置中心动态调整
@ApolloConfigChangeListener
public void onChange(ConfigChangeEvent event) {
if (event.changedKeys().contains("thread.pool.order.core")) {
int newCore = Integer.parseInt(event.getChange("thread.pool.order.core").getNewValue());
threadPoolManager.resize("orderExecutor", newCore, newCore * 2);
}
}
线程池监控与告警
// 结合Micrometer打点监控
@Bean
public MeterBinder threadPoolMetrics(ThreadPoolManager manager) {
return registry -> {
for (Map.Entry<String, ThreadPoolExecutor> e : manager.getPools().entrySet()) {
String name = e.getKey();
ThreadPoolExecutor pool = e.getValue();
Gauge.builder("thread.pool.active", pool, ThreadPoolExecutor::getActiveCount)
.tag("name", name)
.register(registry);
Gauge.builder("thread.pool.queue.size", pool, p -> p.getQueue().size())
.tag("name", name)
.register(registry);
}
};
}
// 队列積压告警规则
// 队列大小超过80%时触发告警
if ((double) pool.getQueue().size() / queueCapacity > 0.8) {
alertManager.send(
AlertLevel.WARNING,
"Thread pool " + name + " queue usage above 80%"
);
}
// 线程池参数设置经验值
// CPU密集型:corePoolSize = N(cpu), maxPoolSize = 2*N(cpu)
// IO密集型:corePoolSize = 2*N(cpu), maxPoolSize = 4*N(cpu)
// 混合型:根据任务耗时测试调整
// N(cpu) = Runtime.getRuntime().availableProcessors()
线程池调优的核心原则是根据任务类型分配资源。CPU密集型任务线程数接近CPU核数,IO密雄型任务线程数可远超CPU核数。拒绝策略的选择需要考虑业务场景,丢弃任务是否可接受、是否需要背压限流。生产环境务必实现动态调整能力,配合配置中心在流量峰值时快速扩容。监控队列积压和拒绝率,及时发现线程池纯锅问题。
原创文章,作者:小编,如若转载,请注明出处:https://www.yunthe.com/java-xian-cheng-chi-pei-zhi-shi-zhan-he-xin-can-shu-diao/