副标题 / 摘要
死锁发生在多个线程互相等待对方持有的资源。本文解释成因、给出示例,并总结规避方法。
目标读者
- 需要理解并发风险的工程师
- 负责系统可靠性的开发者
- 做并发设计评审的技术负责人
背景 / 动机
死锁通常在压力或线上才出现,一旦发生会导致服务完全卡住。
理解死锁条件并提前规避,是并发系统的必修课。
核心概念
- 互斥:资源一次只能被一个线程占用
- 占有且等待:拿着资源还要等另一个资源
- 不可抢占:资源不能被强制夺取
- 循环等待:形成等待环
实践指南 / 步骤
- 统一锁顺序(按固定顺序获取)
- 减少锁数量
- 设置超时与回退
- 用锁分层减少交叉等待
- 监控阻塞与持锁时间
可运行示例
import threading
import time
lock_a = threading.Lock()
lock_b = threading.Lock()
def t1():
with lock_a:
time.sleep(0.1)
with lock_b:
pass
def t2():
with lock_b:
time.sleep(0.1)
with lock_a:
pass
if __name__ == "__main__":
threading.Thread(target=t1).start()
threading.Thread(target=t2).start()
time.sleep(1)
print("可能已死锁")
解释与原理
当 t1 拿着 A 等 B,而 t2 拿着 B 等 A,就形成循环等待。
满足四个必要条件时死锁发生。
常见问题与注意事项
锁顺序能完全避免死锁吗?
在固定顺序下可以显著降低风险。超时锁有什么用?
可避免无限等待,进行回退或重试。死锁与饥饿的区别?
死锁是互相等待,饥饿是一直等不到资源。
最佳实践与建议
- 统一锁顺序是最有效的策略
- 避免嵌套锁或减少锁粒度
- 用监控发现长时间持锁
小结 / 结论
死锁不是偶然,而是设计失误导致。
通过锁顺序、超时与结构化并发,可以大幅减少死锁风险。
参考与延伸阅读
- The Art of Multiprocessor Programming
- Java Concurrency in Practice
- Go/Java/Python 并发锁实践
元信息
- 阅读时长:7~9 分钟
- 标签:死锁、并发、线程安全
- SEO 关键词:Deadlock, 死锁, 锁顺序
- 元描述:解释死锁成因并给出规避策略。
行动号召(CTA)
检查一次你的锁获取顺序,找出是否存在潜在的循环等待。