# 死锁
import threading
import time
# 示例1、死锁
"""
1、使用两个同步锁A和B,同步锁一个锁只能同时调用一次(加锁一次,直到解锁,才能再次加锁)
2、类MyThread有两个方法,分别执行 A方法:加锁A->加锁B->解锁A->解锁B,B方法:加锁B->加锁A->解锁B->解锁A
3、通过sleep模拟IO阻塞
4、在进行加锁后,锁内的代码没执行完就不会解锁,没有解锁的话就会进行阻塞,等待解锁
5、这个例子中会出现执行一段时间后,A方法使用了A锁,要执行加锁B的操作,却发现B方法使用了B锁,要执行对A加锁,而此时A锁和B锁都处于阻塞状态,无法执行下面的解锁操作,导致死锁线程不在继续执行。
"""
class MyThred(threading.Thread):
def a(self):
lockA.acquire() # 加锁A
print(self.name, '加锁A', time.ctime())
time.sleep(3)
lockB.acquire() # 加锁B
print(self.name, '加锁B', time.ctime())
lockA.release() # 解锁A
print(self.name, '解锁A', time.ctime())
lockB.release() # 解锁B
print(self.name, '解锁B', time.ctime())
def b(self):
lockB.acquire() # 加锁B
print(self.name, '加锁B', time.ctime())
time.sleep(3)
lockA.acquire() # 加锁A
print(self.name, '加锁A', time.ctime())
lockB.release() # 解锁B
print(self.name, '解锁B', time.ctime())
lockA.release() # 解锁A
print(self.name, '解锁A', time.ctime())
def run(self):
self.a()
self.b()
if __name__ == '__main__':
lockA = threading.Lock()
lockB = threading.Lock()
t_list = []
for i in range(5):
t_list.append(MyThred())
for t in t_list:
t.start()
for t in t_list:
t.join()
# 示例2、递归锁
"""
1、递归锁是可以被重复使用的
2、内部有一个计时器,一个锁。一个锁可以被多次加锁(lock.acquire()),内部会记录加锁次数,每执行一次解锁(lock.release()),内部会自动减1,由于加锁和解锁的而操作都是针对一把锁,所以不会存在死锁。
3、在下面示例中只有一把锁,被多个线程使用。
4、在使用锁时尽量使用递归锁,避免出现死锁
"""
class MyThred(threading.Thread):
def a(self):
lock.acquire() # 加锁
print(self.name, '加锁', time.ctime())
time.sleep(3)
lock.acquire() # 加锁
print(self.name, '加锁', time.ctime())
lock.release() # 解锁
print(self.name, '解锁', time.ctime())
lock.release() # 解锁
print(self.name, '解锁', time.ctime())
def b(self):
lock.acquire() # 加锁
print(self.name, '加锁', time.ctime())
time.sleep(3)
lock.acquire() # 加锁
print(self.name, '加锁', time.ctime())
lock.release() # 解锁
print(self.name, '解锁', time.ctime())
lock.release() # 解锁
print(self.name, '解锁', time.ctime())
def run(self):
self.a()
self.b()
if __name__ == '__main__':
lock = threading.RLock()
t_list = []
for i in range(5):
t_list.append(MyThred())
for t in t_list:
t.start()
for t in t_list:
t.join()