it编程 > 编程语言 > Java

Java线程池遇到的坑及解决过程

48人参与 • 2026-10-09 • Java

凌晨一点,线上告警炸了——核心服务线程池耗尽,请求堆积超时。重启后短暂恢复,10分钟后再度瘫痪。

你遇到过这种“线程池用着用着就挂了”的灵异事件吗?

今天我要分享的,就是一次因为threadpoolexecutor配置不当引发的,以及我是如何从jvm线程转储和gc日志里扒出真相的。

1. 场景还原:线程池为什么突然“罢工”?

当时我们的订单处理服务采用固定大小的线程池(executors.newfixedthreadpool(20)),日均处理百万级订单。

某次大促期间,监控突然显示活跃线程数从20飙升到200+,最终线程池完全拒绝任务,引发雪崩。

关键现象:

2. 根因:被忽视的阻塞队列膨胀

你以为newfixedthreadpool(20)真的只会用20个线程?看看它的源码实现:

public static executorservice newfixedthreadpool(int nthreads) {
    return new threadpoolexecutor(nthreads, nthreads, 0l, timeunit.milliseconds, 
                                 new linkedblockingqueue<runnable>());
}
  1. linkedblockingqueue默认容量是integer.max_value(约21亿)
  2. 当队列堆积时,外部继续提交任务会导致队列无限膨胀
  3. 堆积的任务持有大量对象引用,引发gc压力
  4. 最终oom或线程阻塞,触发拒绝策略

我们的错误配置让线程池变成了

3. 从错误到救赎:正确配置姿势

错误写法(埋雷版)

executorservice executor = executors.newfixedthreadpool(20);
// 或者
new threadpoolexecutor(20, 20, 0, timeunit.seconds, new linkedblockingqueue<>());

正确写法(止血版)

// 方案1:限制队列容量 + 合理拒绝策略
executorservice executor = new threadpoolexecutor(
    20, 20, 30, timeunit.seconds,
    new linkedblockingqueue<>(1000),  // 明确限制队列长度
    new threadpoolexecutor.callerrunspolicy()  // 让调用线程直接执行
);
// 方案2:使用同步队列(适合短平快任务)
executorservice executor = new threadpoolexecutor(
    20, 200, 60, timeunit.seconds,
    new synchronousqueue<>(),
    new threadfactorybuilder().setnameformat("order-process-%d").build()
);

4. 数据对比:有界 vs 无界队列

压测结果(相同任务负载):

配置方式最大线程数队列峰值gc停顿时间吞吐量
无界队列201.2w1.8s暴跌80%
有界队列+callerruns20800200ms稳定
synchronousqueue动态扩缩容050ms最高

5. 避坑清单:线程池的暗礁们

关键改进点:

强制设置合理的队列上限(根据内存和延迟要求)

队列选择陷阱

拒绝策略误区

最佳实践:日志记录 + 监控报警 + 适当降级

任务里忘了捕获异常?线程会悄悄消失:

   executor.execute(() -> {
       try {
           dobusiness();
       } catch (exception e) { // 必须捕获!
           log.error("task failed", e);
       }
   });

核心结论:

线程池不是银弹,executors快捷方法藏着毒。永远手动构造threadpoolexecutor,明确所有参数!

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。

赞 (0)

您想发表意见!!点此发布评论

推荐阅读

Spring 过滤器与拦截器深度对比:Filter、Interceptor 的区别、执行顺序与选型

10-09

Java8 LocalDateTime是什么?日期时间转换全解析

10-09

Maven私有仓库怎么配置?从零搭建Nexus仓库教程

10-09

Java LocalDateTime用法详解,日期时间处理不再难

10-09

Spring MVC 架构与请求处理全链路解析:从 DispatcherServlet 到响应返回

10-09

Spring Boot集成Jasypt配置加密实战:从接入到避坑

10-09

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论