jstack快速定位线程卡死需用-l参数抓锁信息,重点分析blocked、deadlock及parking/waiting锁地址关联;visualvm远程连接须配全4个jmx参数并设-djava.rmi.server.hostname;线程泄漏要查活动线程曲线和thread实例数。

线程卡死时,jstack 怎么快速抓到罪魁祸首
直接用 jstack 抓堆栈是最快定位线程阻塞/死锁的方式,但很多人输完命令只看到一堆 java.lang.Thread.State: WAITING 就懵了——关键不是状态本身,而是它停在哪一行、持有什么锁、在等谁释放。
- 先确认目标进程 PID:
jps -l或ps aux | grep java - 执行
jstack -l <pid> > thread_dump.txt</pid>,-l参数必须加,否则看不到锁信息(比如locked或waiting to lock) - 重点关注
java.lang.Thread.State: BLOCKED和deadlock段落;WAITING要结合at行和locked/waiting to lock一起看 - 别用
jstack <pid></pid>直接输出到终端,长堆栈容易刷屏丢失关键行;重定向到文件后用grep -A 10 -B 5 "BLOCKED\|deadlock"快速过滤
VisualVM 连不上远程 Java 进程?-Dcom.sun.management.jmxremote 配置漏了哪几项
VisualVM 本地连本机进程没问题,一换远程就显示“无法连接”,大概率是 JVM 启动参数没配全,或者防火墙/SELinux 拦了 JMX 端口。
- 必须同时设置这 4 个系统属性:
-Dcom.sun.management.jmxremote、-Dcom.sun.management.jmxremote.port=9999、-Dcom.sun.management.jmxremote.authenticate=false、-Dcom.sun.management.jmxremote.ssl=false -
-Djava.rmi.server.hostname=这一项最容易漏——如果服务器有多个网卡或用了 Docker,RMI 默认返回 localhost 或内网地址,导致 VisualVM 连过去后二次握手失败 - 远程端口(如 9999)要开放:检查
iptables或firewalld,云服务器还得看安全组 - VisualVM 插件不用额外装,自带的 “MBeans” 和 “Threads” 标签页足够查线程状态;点开线程名就能看到实时堆栈和 CPU 时间
jstack 输出里 parking to wait for 和 waiting on condition 到底在等什么
这两类状态常被误认为“空闲”,其实背后是典型的同步等待:前者多见于 LockSupport.park()(比如 ReentrantLock、ThreadPoolExecutor 工作线程),后者常见于 Object.wait() 或 Condition.await()。
-
parking to wait for:说明线程正通过 AQS 等待获取某个锁对象,去堆栈里找acquireQueued或lockInterruptibly调用位置 -
waiting on condition:通常对应Condition.await(),要看前一行的at java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await,再往上翻调用链,找到业务代码里condition.await()的位置 - 注意:这些锁地址(如
)在同一次jstack输出中是唯一的,可跨线程搜索,确认哪个线程持有它、是否已超时未唤醒
用 VisualVM 查线程泄漏,为什么“线程数持续上涨”却看不到新线程名
线程数涨得慢、名字又都是 pool-1-thread-xx 这种动态生成的,靠肉眼数名字根本不可靠;真正该盯的是“活动线程数”曲线和线程生命周期分布。
立即学习“Java免费学习笔记(深入)”;
- 打开 VisualVM 的 “Threads” 标签页,勾选 “Live threads only”,再点右上角 “Thread dump” 按钮,不要只看当前快照——间隔 30 秒连续抓 3 次,对比
java.lang.Thread实例数是否稳定 - 导出堆内存快照(Heap Dump)后,在 “Classes” 视图里搜
java.lang.Thread,看实例数是否远超预期(比如线程池核心数 × 2) - 常见陷阱:线程池
allowCoreThreadTimeOut(true)没设,导致核心线程永不销毁;或ThreadLocal持有大对象 + 线程复用,造成内存泄漏间接拖慢线程回收 - 如果线程名都一样,重点看堆栈最顶层:是不是全卡在
getTask()(空闲等待)、还是全堵在某个数据库连接获取、或是反复抛异常后没正确 shutdown
locked 地址里串起持有者和等待者。JDK 自带工具够用,但漏掉 -l 或 java.rmi.server.hostname 这种细节,就等于没打开门。








