unable to create new native thread 是操作系统拒绝分配线程资源的硬限制异常,根因分系统层、jvm层、代码层三层,需按序排查:先验证线程数、栈占用及系统限额,再检查-xss、线程池配置与threadlocal泄漏。

先确认是不是真爆了:别猜,看数字
第一步永远是验证,而不是改代码或调参数:
- 查当前 JVM 进程线程数:
ps -T -p <pid> | wc -l</pid>(结果减 1 才是真实线程数) - 查系统对单进程的线程上限:
cat /proc/<pid>/limits | grep "Max processes"</pid>(对应RLIMIT_NPROC) - 查全局线程上限:
cat /proc/sys/kernel/threads-max - 查线程栈总占用(粗估):
pstack <pid> | grep "Thread" | wc -l</pid>,再乘默认栈大小(Linux x64 通常 1MB)
根因分三层:系统层、JVM 层、代码层
问题一定落在其中一层,按顺序排查效率最高:
-
系统层:用户级进程数限制(
ulimit -u)、内核线程总数上限(threads-max)、虚拟内存映射区不足(vm.max_map_count)——这些在容器或云主机上常被默认压得很低 - JVM 层:-Xss 设置过大(如设成 4MB),导致少量线程就吃光可用地址空间;或堆内存设得过大,挤压了线程栈可分配的虚拟内存空间
-
代码层:最常见——
Executors.newCachedThreadPool()在流量突增时疯狂建线程;循环里无节制submit();线程池用LinkedBlockingQueue(无界)+ 过大的maximumPoolSize;或ThreadLocal泄漏导致线程不敢回收
生产级线程池配置铁律
2026年一线大厂线上服务已基本淘汰 Executors 工具类,全部手配 ThreadPoolExecutor:
- 核心线程数 =
Runtime.getRuntime().availableProcessors()(CPU 密集型)或 ×2~4(IO 密集型,需压测验证) - 最大线程数必须有明确上限,禁用
Integer.MAX_VALUE - 任务队列必须有界:
new ArrayBlockingQueue(512)或(1024),配合拒绝策略(推荐CallerRunsPolicy或自定义日志告警策略) - 线程工厂必须命名:
ThreadFactoryBuilder.setNameFormat("order-async-%d"),方便jstack一眼识别来源 - 务必设置
allowCoreThreadTimeOut(true)(尤其 IO 密集型),让空闲核心线程也能回收
线程泄漏的典型信号与止血操作
线程数缓慢上涨、长期不降,大概率是泄漏。重点关注:
-
jstack <pid></pid>输出中大量线程状态为TIMED_WAITING (parking),但堆栈停在Unsafe.park且 Key 是 null —— 这是ThreadLocalMap中 key 被 GC、value 却没清理的典型痕迹 - 所有使用
ThreadLocal的地方(尤其是拦截器、过滤器、AOP),必须在 finally 块中调用remove() - 线程池 shutdown 后仍有活跃线程?检查是否漏掉
shutdownNow()或未 awaitTermination - 用
TransmittableThreadLocal替代原生InheritableThreadLocal,避免异步线程池中上下文传递引发的隐式引用链











