高 进阶
死锁与处理策略#
一句话答案#
死锁四必要条件:互斥/占有等待/不可剥夺/循环等待,预防方式:破坏其中一个条件(如超时释放/按序申请)。
核心要点
预防:
- 破坏占有等待:一次性申请所有资源
- 破坏不可剥夺:超时释放
- 破坏循环等待:资源排序,按序申请
检测: 资源分配图 / jstack 线程 dump / SHOW ENGINE INNODB STATUS
面试回答(2分钟版)
死锁是指两个或多个进程互相持有对方所需的资源并等待对方释放,导致所有相关进程永久阻塞。死锁的产生需要同时满足四个必要条件:互斥即资源同一时刻只能被一个进程使用、占有等待即进程持有资源的同时等待其他资源、不可剥夺即已分配的资源不能被强制收回、循环等待即存在进程间的环形等待链。预防死锁的思路就是破坏其中至少一个条件:破坏占有等待可以要求进程一次性申请所有需要的资源;破坏不可剥夺可以设置超时机制获取不到就释放已持有的资源,比如 Java 的 tryLock 带超时;破坏循环等待可以对资源编号按固定顺序申请,保证不会形成环路。死锁检测方面,Java 中可以用 jstack 打印线程转储查看 BLOCKED 状态的线程和锁等待关系,JMX 的 ThreadMXBean 也能编程检测死锁。MySQL 的 InnoDB 引擎内置了死锁检测机制,通过 SHOW ENGINE INNODB STATUS 可以查看最近的死锁信息,InnoDB 会自动选择代价小的事务回滚来打破死锁。
追问与易错
追问方向:
- “怎么检测 Java 死锁?”→ jstack 打印线程转储看 BLOCKED 状态和锁等待链、JMX 的 ThreadMXBean.findDeadlockedThreads() 编程检测、jconsole 图形化查看
- “数据库死锁和 Java 死锁排查区别?”→ Java 死锁靠 jstack 看线程;MySQL InnoDB 内置死锁检测自动回滚代价小的事务,用 SHOW ENGINE INNODB STATUS 查看死锁日志
- “哲学家就餐问题怎么解决?”→ 破坏循环等待:给筷子编号按序申请、限制同时进餐人数(信号量)、引入服务员统一分配资源(资源分配器模式)
易错点:
- ❌ 避免所有嵌套锁就不会死锁——顺序不一致也会
- ❌ 死锁只影响两个线程——可能是多线程循环等待