大厂代码评审需关注运行态线程数是否逼近系统上限,而非仅统计start()调用次数;应结合Thread.activeCount()、/proc/{pid}/status中Threads字段及threads-max交叉验证,重点审查线程池参数、队列类型、拒绝策略,并识别隐式线程创建点,交付物须含可量化的线程水位基线。

在大厂代码评审中,单纯检查 start() 调用次数无法反映真实线程负荷——关键要看「运行态线程数是否逼近系统上限」。评审时需结合线程计数器(如 Thread.activeCount()、/proc/{pid}/status 中的 Threads: 字段)与硬件约束交叉验证,而非只数代码里写了几个 new Thread().start()。
看线程池配置,不看裸 new Thread
大厂生产代码几乎禁用裸 Thread 创建。评审重点应是线程池参数是否合理:
- 确认
corePoolSize和maximumPoolSize是否按任务类型区分:CPU 密集型建议设为CPU核心数 + 1,IO 密集型建议不低于CPU核心数 × 4 - 检查
workQueue类型:禁用无界队列(如LinkedBlockingQueue不设容量),优先选用有界队列(如ArrayBlockingQueue)并明确容量值 - 核实拒绝策略:禁止使用默认
AbortPolicy(直接抛异常),必须自定义策略记录日志或降级,确保可追溯被拒任务
用运行时线程计数器做硬性校验
静态代码分析只能看到“可能创建多少线程”,真正压测和线上监控靠的是实时线程计数器:
- Java 进程内可用
ManagementFactory.getThreadMXBean().getThreadCount()获取当前总线程数 - Linux 系统级限制查
cat /proc/sys/kernel/threads-max,典型值在 1024–65536 之间,低端设备可能仅 512 - 单进程当前线程数查
cat /proc/{pid}/status | grep Threads,若接近threads-max的 80%,即属高风险 - 评审时若发现某模块在高峰期该值持续 > 3000(而
threads-max=4096),必须要求优化线程复用或拆分任务
识别隐式线程膨胀点
很多 start() 并不显式出现在主流程,却在依赖库或框架中悄悄触发:
- 检查是否滥用
CompletableFuture.runAsync()(默认使用ForkJoinPool.commonPool(),但部分场景会新建线程) - 排查第三方 SDK:如某些旧版 HTTP 客户端(OkHttp 2.x)、数据库连接池(Druid 初始化阶段)会自行创建守护线程
- 注意定时任务框架(如 Quartz、Spring @Scheduled):每个
@Scheduled方法默认独占一个线程,大量定时任务等于大量常驻线程 - 评审注释中应强制要求:所有隐式创建线程的调用,必须标注预期线程数及生命周期(例如:“此处触发 OkHttp 内部 dispatcher,新增最多 2 个后台线程,存活至应用关闭”)
评审交付物必须包含线程水位基线
不能只说“已优化”,要给出可验证的数据:
- 提交 PR 时需附压测报告片段:标明 QPS 500 下,
ThreadCount峰值、threads-max比值、GC 次数变化 - 监控埋点必须覆盖:线程池的
getActiveCount()、getPoolSize()、getTaskCount(),而非仅看业务指标 - 上线前检查项清单中增加一条:“确认
/proc/{pid}/status中 Threads 数值在预估峰值流量下 ≤ threads-max × 0.75”

















