1.概念:

资源加锁是怎么回事,其实并不是给资源加锁, 而是用锁去锁定资源,你可以定义多个锁, 像下面的代码, 当你需要独占某一资源时,任何一个锁都可以锁这个资源,就好比你用不同的锁都可以把相同的一个门锁住是一个道理.

import  threading   
import  time   
counter = 0 
counter_lock = threading.Lock() #只是定义一个锁,并不是给资源加锁,你可以定义多个锁,像下两行代码,当你需要占用这个资源时,任何一个锁都可以锁这个资源 
counter_lock2 = threading.Lock()  
counter_lock3 = threading.Lock() 
#可以使用上边三个锁的任何一个来锁定资源 
class  MyThread(threading.Thread):#使用类定义thread,继承threading.Thread 
     def  __init__(self,name):   
        threading.Thread.__init__(self)   
        self.name = "Thread-" + str(name) 
     def run(self):   #run函数必须实现 
         global counter,counter_lock #多线程是共享资源的,使用全局变量 
         time.sleep(1);   
         if counter_lock.acquire(): #当需要独占counter资源时,必须先锁定,这个锁可以是任意的一个锁,可以使用上边定义的3个锁中的任意一个 
            counter += 1    
            print("I am %s, set counter:%s"  % (self.name,counter))
            counter_lock.release() #使用完counter资源必须要将这个锁打开,让其他线程使用 
if  __name__ ==  "__main__":   
    for i in range(1,10):   
        my_thread = MyThread(i) 
        my_thread.start()

2. 线程不安全:

最普通的一个多线程小例子。我一笔带过地讲一讲,我创建了一个继承Thread类的子类MyThread,作为我们的线程启动类。按照规定,重写Thread的run方法,我们的线程启动起来后会自动调用该方法。于是我首先创建了10个线程,并将其加入列表中。再使用一个for循环,开启每个线程。在使用一个for循环,调用join方法等待所有线程结束才退出主线程。

这段代码看似简单,但实际上隐藏着一个很大的问题,只是在这里没有体现出来。你真的以为我创建了10个线程,并按顺序调用了这10个线程,每个线程为counter增加了1。

实际上,有可能是A线程执行了n++,再C线程执行了n++,再B线程执行n++。

这里涉及到一个“锁”的问题,如果有多个线程同时操作一个对象,如果没有很好地保护该对象,会造成程序结果的不可预期(比如我们在每个线程的run方法中加入一个time.sleep(1),并同时输出线程名称,则我们会发现,输出会乱七八糟。因为可能我们的一个print语句只打印出一半的字符,这个线程就被暂停,执行另一个去了,所以我们看到的结果很乱),这种现象叫做“线程不安全”

3. 线程锁:

于是,Threading模块为我们提供了一个类,Threading.Lock,锁。我们创建一个该类对象,在线程函数执行前,“抢占”该锁,执行完成后,“释放”该锁,则我们确保了每次只有一个线程占有该锁。这时候对一个公共的对象进行操作,则不会发生线程不安全的现象了。

于是,我们把代码更改如下:

# coding : uft-8
import threading, time
class MyThread(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
    def run(self):
        global n, lock
        time.sleep(1)
        if lock.acquire():
            print(n , self.name)
            n += 1
            lock.release()
if "__main__" == __name__:
    n = 1
    ThreadList = []
    lock = threading.Lock()
    for i in range(1, 10):
        t = MyThread()
        ThreadList.append(t)
    for t in ThreadList:
        t.start()
    for t in ThreadList:
        t.join()

 

结果如下

Python Manager 加锁 python中的锁_for循环

使用锁

import threading
import time
start_time = time.time()
def add():
    for i in range(3):
        print('a的值:',i)
        time.sleep(1)
def sj():
    for i in range(3):
        print('b的值:',i)
        time.sleep(1)
a = threading.Thread(target = add)
a.start()
b = threading.Thread(target = sj)
b.start()
while threading.active_count()!=1:
    pass
end_time = time.time()
print(end_time-start_time)

Python Manager 加锁 python中的锁_Python Manager 加锁_02

import threading
import time
lock = threading.Lock()
start_time = time.time()
def add():
    lock.acquire()
    for i in range(3):
        print('a的值:',i)
        time.sleep(1)
    lock.release()
def sj():
    lock.acquire()
    for i in range(3):
        print('b的值:',i)
        time.sleep(1)
    lock.release()
a = threading.Thread(target = add)
a.start()
b = threading.Thread(target = sj)
b.start()
while threading.active_count()!=1:
    pass
end_time = time.time()
print(end_time-start_time)

Python Manager 加锁 python中的锁_多线程_03

最后,anyway,总结一下,threading.Lock就是避免资源抢占的问题,直接对比最后两部分代码就很清楚的理解,就像我们同时在做烧水和炒菜这两件事,使用threading.Lock保证了我们每一次都是先专注做完一件事。