锁的作用是在多个线程访问同一个资源时对资源进行保护,防止多线程操作造成结果不解预测
1.互斥锁
import threading
num = 0
mutex = threading.Lock();
def cal(i):
#上锁
mutex.acquire()
global num
num += i
#解锁
mutex.release()
lst = []
for i in range(5):
t = threading.Thread(target=cal,args=(i,))
lst.append(t)
t.start()
for t in lst:
t.join()
print(num)
2.可重入锁
可重入锁是用来解决循环加锁造成的死锁问题。
互斥锁连续上锁两次以上便会陷入死锁状态,如果要使用同一把锁进行多次锁操作,必须使用可重入锁RLock。
RLock中维护了一个Lock对象和一个counter,counter中记录了锁acquire的次数,使得可以对锁进行多次的acquire操作。
只有在所有的acquire被release之后,其他线程才能够获得资源。
#如果使用了Lock便会死锁
# mutex = threading.Lock();
mutex = threading.RLock();
num = 0
def plus():
mutex.acquire()
print("plus lock")
global num
num += 1
mutex.release()
print("plus release")
def mimus():
mutex.acquire()
print("mimus lock")
global num
num -= 1
mutex.release()
print("mimus release")
def run():
mutex.acquire()
plus()
print("-----------")
mimus()
mutex.release()
for i in range(5):
t = threading.Thread(target=run)
t.start()
3.信号量
互斥锁同时允许一个线程访问资源,而信号量同时允许一组线程访问资源。
连接池就是信号量的运用。
import threading
import time
#一个最大为5的信号量
semaphore = threading.BoundedSemaphore(5)
def func(i):
semaphore.acquire()
print("member%d访问" %i)
time.sleep(i)
semaphore.release()
for i in range(20):
t= threading.Thread(target = func,args = (i,))
t.start()
从运行结果可以看出,持续会维持在同时最多只有5个线程可以进行访问,当有信号量release了才会用新的进程递补