python-多线程死锁 作者:马育民 • 2019-02-24 14:24 • 阅读:10176 # 说明 死锁是指两个或两个以上的线程,互相持有对方需要的同步资源,都在等对方放弃该资源,导致互相等待,都无法继续执行。 这是严重问题,因为死锁会让线程处于阻塞状态,**无法完成任务** ### 例子1 [![](http://www.malaoshi.top/upload/0/0/1EF2r5leCYDf.jpg)](http://www.malaoshi.top/upload/0/0/1EF2r5leCYDf.jpg) 两只羊都需要用到独木桥,都在等对方放弃独木桥,导致互相等待,都无法过桥 ### 例子2 面试官:我们需要有工作经验的员工 面试人员:那你得让我工作我才有工作经验啊 面试官:你没有工作经验我们怎么招聘你 面试人员:你不让我工作我哪里来的工作经验 ### 例子3 张三和李四大家,互相揪住领子, 张三说:你先放手,我就放手 李四说:你先放手,我就放手 两个人都在等对方放手,导致互相等待,都无法放手 # 死锁 原因 和 解决 ### 死锁的原因 下面四个条件都成立的时候,就形成死锁: 1. 互斥使用:一个资源只能被一个线程占有,当该资源被占有后其他线程就只能等待 2. 不可剥夺条件(不可抢占):当一个线程不主动释放资源时,该资源一直被此线程占有 3. 请求并持有条件(请求和保持):线程已经拥有了一个资源后,又尝试请求新的资源 4. 环路等待条件(循环等待):P1占有P2的资源,P2占有P3的资源,P3占有P1的资源。这样就形成了一个等待环路 ### 死锁的解决 死锁的情况下,如果打破上述任何一个条件,就可以解决死锁,如:不要嵌套使用 `synchronized` ### 案例 [![](http://www.malaoshi.top/upload/0/0/1EF2r69hYbKk.png)](http://www.malaoshi.top/upload/0/0/1EF2r69hYbKk.png) ``` #coding=utf-8 import threading import time def task1(): t=threading.current_thread() #lock1申请锁,成功 if lock1.acquire(): print("%s lock1申请锁"%t.name) time.sleep(1) #lock2申请锁,但在20行已经申请锁,所以等待释放 lock2.acquire() print("%s lock2申请锁"%t.name) lock2.release() lock1.release() def task2(): t=threading.current_thread() #lock2申请锁,成功 if lock2.acquire(): print("%s lock2申请锁"%t.name) time.sleep(1) #lock1申请锁,但在8行已经申请锁,所以等待释放 lock1.acquire() print("%s lock1申请锁"%t.name) lock1.release() lock2.release() if __name__ == "__main__": lock1=threading.Lock() lock2=threading.Lock() t=threading.Thread(target=task1) t2=threading.Thread(target=task2) #启动线程 t.start() t2.start() ``` **执行结果:** [![](http://www.malaoshi.top/upload/0/0/1EF2r6KGiMeo.png)](http://www.malaoshi.top/upload/0/0/1EF2r6KGiMeo.png) **说明:** 12行,lock2申请锁,但在20行已经申请锁,所以等待释放 23行,lock1申请锁,但在8行已经申请锁,所以等待释放 # 避免死锁 在有些情况下死锁是可以避免的。 1. 加锁时限 2. 加锁顺序 3. 死锁检测 ### 给锁加时间限制 ``` #coding=utf-8 import threading import time def task1(): t=threading.current_thread() #申请lock1 lock1.acquire() print("%s lock1申请锁"%t.name) time.sleep(1) #申请lock2,如果3秒内申请不到,返回False if lock2.acquire(True,3): print("%s lock2申请锁"%t.name) lock2.release() lock1.release() def task2(): t=threading.current_thread() #申请lock2 lock2.acquire() print("%s lock2申请锁"%t.name) time.sleep(1) #申请lock1,如果3秒内申请不到,返回False if lock1.acquire(True,3): print("%s lock1申请锁"%t.name) lock1.release() lock2.release() if __name__ == "__main__": lock1=threading.Lock() lock2=threading.Lock() t=threading.Thread(target=task1) t2=threading.Thread(target=task2) #启动线程 t.start() t2.start() ``` 原文出处:http://malaoshi.top/show_1EF2r6ZE0Ohq.html