锁的作用是在多个线程访问同一个资源时对资源进行保护,防止多线程操作造成结果不解预测
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了才会用新的进程递补