死锁
死锁是多个执行主体因互相等待资源而无法继续推进的状态。本文讨论通用锁与资源等待;具体数据库检测和重试见数据库死锁文章。
1. 面试核心
先记住这几条,再读正文- 经典资源死锁同时涉及互斥、占有并等待、不可强制剥夺和循环等待。
- 统一获取锁的顺序可以破坏循环等待。
- 超时只是退出等待的机制,仍需释放资源、恢复状态并控制重试。
2. 等待环
线程 T1:持有 A,等待 B
线程 T2:持有 B,等待 A
若 A、B 都只能由一个线程持有,且只有持有者正常完成后才释放,两者都无法完成。可以把等待关系画成 T1 → T2 → T1。
每类资源只有一个实例时,资源等待图中的环可以作为经典死锁判断依据;存在多实例资源时,仅有环不一定足以判定死锁。回答时先说明模型。
3. 预防与恢复
让所有线程都先获取 A 再获取 B,可避免这一对锁形成循环等待。多个业务对象需要根据稳定、统一的键确定锁顺序,不能由调用参数的排列顺序临时决定。
也可以尝试一次性获取全部资源;如果失败就释放已获得部分,稍后重试。这样要处理重试饥饿和频繁碰撞。检测到死锁后中止一个任务,必须确保它持有的资源和业务中间状态都能恢复。
4. 使用边界
长时间等待可能来自慢 I/O、持锁线程繁忙或资源不足,并不必然形成死锁。排查时需要线程栈、锁持有者和等待链证据。
活锁中线程仍在运行和互相让步,却没有有效进展;饥饿则是某个任务长期得不到资源。对外部系统的调用超时,也不表示对端没有执行成功。数据库中的等待处理参见数据库死锁。
5 · 面试题卡片
先想答案,再翻面题目来自公开面经。点任意一张进入翻卡,可左右切换,看完回到这里。
逐张翻看 1 张 →5.1 死锁需要哪些条件,如何避免两个线程反向获取锁造成的死锁?
出现公司:字节跳动
考察重点:经典死锁条件、等待环与统一加锁顺序的作用。
参考回答
在经典模型下,互斥、占有并等待、不可剥夺和循环等待共同构成死锁条件。反向加锁例子可以让所有线程按统一顺序获取两把锁,破坏循环等待。若使用超时,需要失败后释放已持有资源并恢复状态,再采用有界退避重试,不能只重新调用而保留旧锁。