死锁典型模式是多线程以不同顺序获取同一组对象锁,如线程1先锁objA再锁objB、线程2反之,导致互相等待;jstack可直接定位,输出“Found one Java-level deadlock:”;避免关键是固定锁顺序、用tryLock+回退、优先并发工具类。

死锁发生的典型代码模式
Java中死锁最常见于多个线程以不同顺序获取同一组Object锁(或synchronized块),且都持有部分锁、等待对方释放。比如两个线程分别执行:
Thread 1: synchronized(objA) { ... synchronized(objB) { ... } }
Thread 2: synchronized(objB) { ... synchronized(objA) { ... } }
一旦线程1拿到objA、线程2拿到objB,双方就会永久阻塞——JVM不会自动检测或中断这种等待。
如何用jstack定位死锁
运行中的Java进程若疑似卡死,优先用jstack抓取线程快照,它能直接标出死锁线程及锁依赖链:
- 执行
jstack,输出中搜索Found one Java-level deadlock: - 若没找到,加参数
-l(jstack -l)可显示更详细的锁信息,包括ReentrantLock持有者 - 注意:
jstack必须由与目标JVM相同用户执行,否则可能无权限读取
避免嵌套锁的实用策略
根本解法不是“加超时”或“重试”,而是从设计上消除锁序不一致:
本程序源码为asp与acc编写,并没有花哨的界面与繁琐的功能,维护简单方便,只要你有一些点点asp的基础,二次开发易如反掌。 1.功能包括产品,新闻,留言簿,招聘,下载,...是大部分中小型的企业建站的首选。本程序是免费开源,只为大家学习之用。如果用于商业,版权问题概不负责。1.采用asp+access更加适合中小企业的网站模式。 2.网站页面div+css兼容目前所有主流浏览器,ie6+,Ch
立即学习“Java免费学习笔记(深入)”;
- 所有线程按**固定顺序**获取锁,例如约定按
System.identityHashCode(objA) 决定先锁哪个对象 - 用
tryLock(long, TimeUnit)替代synchronized,失败后释放已持锁并重试(需配合lockInterruptibly()处理中断) - 优先使用
java.util.concurrent工具类(如ConcurrentHashMap、AtomicInteger),它们内部不依赖用户显式锁,天然规避死锁风险
ReentrantLock与synchronized的死锁差异
synchronized是JVM层实现,不可中断、无超时;而ReentrantLock支持更精细控制,但误用反而更容易引发隐蔽死锁:
- 忘记在
finally块中调用unlock()→ 锁永远不释放 → 其他线程卡死 - 同一个
ReentrantLock实例被不同线程反复lock()但未配对unlock()→ 实际等效于无限嵌套 -
lockInterruptibly()虽可响应中断,但如果线程在等待锁时被中断,需确保清理资源,否则状态可能不一致
真正难防的不是“两个锁互相等”,而是锁粒度混乱 + 异常路径遗漏 + 多层调用隐藏了锁获取逻辑——这些地方最容易漏掉unlock()或搞错锁顺序。










