死锁指两个或多个线程/进程互相持有对方需要的资源并无限等待,谁都无法继续推进的状态。经典例子:线程 A 持有锁 1 申请锁 2,线程 B 持有锁 2 申请锁 1,双方互相等待,永久阻塞。

死锁产生的四个必要条件(同时满足才会发生):

  1. 互斥:资源同一时刻只能被一个线程占有。
  2. 占有且等待:线程持有至少一个资源,同时等待被他人占有的资源。
  3. 不可剥夺:已分配的资源不能被强制抢走,只能由持有者主动释放。
  4. 循环等待:存在线程-资源的环形等待链(A 等 B、B 等 A)。

展开解析:四个条件是"必要"而非"充分"的表述要准确——破坏任意一条即可预防死锁,常用手段:

  • 破坏循环等待:给锁规定全局顺序,所有线程按同一顺序加锁(最实用)。
  • 破坏占有且等待:一次性申请全部资源,或用 tryLock 超时后释放已持有的锁重试。
  • 破坏不可剥夺:允许抢占资源(实现复杂)。

易错点:还有"活锁"(线程不断重试互相让步但无进展)和"饥饿",它们不是死锁。

追问方向:死锁检测(等待图/银行家算法)、如何排查线上死锁(jstack、gdb 看线程持有的锁)。