如何排查死锁 java
排查 Java 死锁的方法
使用 jstack 工具分析线程转储
通过命令行运行 jstack -l <pid> 生成线程转储文件,其中 <pid> 是 Java 进程的 ID。在输出中搜索 deadlock 关键词,工具会自动标记死锁的线程及其持有的锁资源。
通过线程转储识别死锁环 检查线程转储中是否存在循环等待链,例如:线程 A 持有锁 L1 并等待锁 L2,而线程 B 持有锁 L2 并等待锁 L1。这种相互等待的环状结构是死锁的典型特征。
编程式检测死锁
利用 ThreadMXBean API 主动检测死锁:

ThreadMXBean bean = ManagementFactory.getThreadMXBean();
long[] threadIds = bean.findDeadlockedThreads();
if (threadIds != null) {
ThreadInfo[] infos = bean.getThreadInfo(threadIds);
for (ThreadInfo info : infos) {
System.out.println(info.getThreadName() + " 被阻塞在 " + info.getLockName());
}
}
可视化工具辅助分析 使用 JVisualVM 或 YourKit 等 Profiler 工具,它们提供图形化界面展示线程状态和锁依赖关系,能直观呈现死锁位置。
日志与监控 在关键同步代码块添加日志,记录锁的获取和释放顺序。结合 APM 工具(如 SkyWalking)监控长时间阻塞的线程。

预防死锁的最佳实践
避免嵌套锁 尽量减少同步块的嵌套层级,按照固定全局顺序获取多个锁。例如对所有需要锁的资源进行排序,始终按相同顺序申请。
使用超时机制
采用 tryLock() 带有超时参数的锁获取方式:
if (lock1.tryLock(1, TimeUnit.SECONDS)) {
try {
if (lock2.tryLock(1, TimeUnit.SECONDS)) {
try {
// 临界区代码
} finally {
lock2.unlock();
}
}
} finally {
lock1.unlock();
}
}
降低锁粒度
将大锁拆分为多个小锁,或使用并发集合(如 ConcurrentHashMap)替代同步块。考虑使用读写锁(ReentrantReadWriteLock)提升读多写少场景的性能。
静态分析工具 在开发阶段使用 FindBugs 或 SpotBugs 扫描潜在的锁顺序问题。SonarQube 等代码质量平台也能检测可疑的同步模式。






