锁定方法acquire可以有一个blocking参数。
如果设定blocking为True,则当前线程会堵塞,直到获取到这个锁为止(如果没有指定,那么默认为True)
如果设定blocking为False,则当前线程不会堵塞
from threading import Thread, Lock
import time
num =0 # 资源竞争问题
mutex= Lock() # 创建一个互斥锁
def fun1():
global num
for i in range(1000000):
while True:
# mutex.acquire(blocking=False) # 通过blocking参数,如果设置为True表示acquire函数属于阻塞方式,否则,非阻塞方法
result =mutex.acquire(False) # 通过blocking参数,如果设置为True表示acquire函数属于阻塞方式,否则,非阻塞方法
# acquire返回值result的含义
# 如果返回True,表示上锁成功 (意思是,锁原本处于未上锁状态,此次调用成功将锁设置为上锁状态)
# 如果返回False, 表示上锁失败 (意思是,锁原本就属于上锁状态,此次调用再想上锁是不能完成)
if result:
# result为True,表示成功上锁,可以修改资源
num += 1
mutex.release() # 释放锁,表示将锁设置为打开状态
break
else:
# result为False,表示没有成功上锁,所以尝试下一次操作
print("线程1 虽然没有拿到锁,但是可以唱歌")
time.sleep(0.1)
def fun2():
global num
for i in range(1000000):
while True:
result = mutex.acquire(False)
if result:
num += 1
mutex.release() # 释放锁,表示将锁设置为打开状态
break
else:
print("线程2 虽然没有拿到锁,但是可以跳舞")
time.sleep(0.1)
t1 =Thread(target=fun1) # 创建一个线程对象
t2 =Thread(target=fun2) # 创建一个线程对象
t1.start() # 开启线程的执行
t2.start()
t1.join() # 回收线程资源
t2.join()
print(num)
上锁解锁过程
当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。
每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。
线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
锁的好处:
确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁