关于线程锁的认识
一、关于线程锁的认识
- 1、
python
多线程针对IO
密集型的操作,遇到IO
操作就会切换线程。 - 2、对于多线程同时操作一个数据的时候,我们为了数据的准确性,需要给每个执行动作加上一个线程锁(大白话理解:我们上公共厕所的时候,都会关门上锁,当你出来的时候,别人才可以进去,线程锁也是这个概念,必须等一个线程执行完后才能切换下一个线程)
- 3、在现实生活中我们常见场景:同一银行账户下,有人存钱,有人取钱,不加锁的时候就会造成,没钱也可以取钱出来
二、同步锁锁对同一个数据进行操作
1、实现代码
import threading total = 0 def add(): global total for i in range(1000000): total += 1 def reduce(): global total for i in range(1000000): total -= 1 if __name__ == "__main__": thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=reduce) thread1.start() thread2.start() thread1.join() thread2.join() print('计算结果:', total)
2、上面代码每次运行的结果都不一样,主要是两个线程之间不停的抢占资源(切换线程造成的)
3、使用线程锁,把需要锁住的部分锁住
import threading total = 0 # 创建一把锁 gLock = threading.Lock() def add(): global total gLock.acquire() for i in range(1000000): total += 1 gLock.release() def reduce(): global total gLock.acquire() for i in range(1000000): total -= 1 gLock.release() if __name__ == "__main__": thread1 = threading.Thread(target=add) thread2 = threading.Thread(target=reduce) thread1.start() thread2.start() thread1.join() thread2.join() print('计算结果:', total)
二、python
中的死锁
是指两个以上的线程同时执行的时候,因相互争夺资源造成一种互相等待的现象,谁也不先释放自己的锁,如果没有外力的情况下,就一直僵持下去,造成死锁的现象,称为死锁。
也许对上面的定义不太理解,举个生活中的例子:小明手上有个苹果,小红手上有香蕉,他们都想交换对方手上的水果,但是两个人没一个人愿意主动或者说是不放心对方(不肯交换),如果没有别人的介入,他们两只能干等对方先主动提出来,这就是死锁的现象
1、产生死锁的代码
import threading import time class MyThread(threading.Thread): def func1(self): lockA.acquire() print(self.name, '锁A', time.ctime()) lockB.acquire() print(self.name, '锁B', time.ctime()) lockB.release() lockA.release() def func2(self): lockB.acquire() print(self.name, '锁B', time.ctime()) time.sleep(3) lockA.acquire() print(self.name, '锁A', time.ctime()) lockA.release() lockB.release() def run(self): self.func1() self.func2() # 创建一把锁A lockA = threading.Lock() # 创建一把锁B lockB = threading.Lock() if __name__ == "__main__": for i in range(5): t = MyThread() t.start()
2、输出结果
Thread-1 锁A Sun Jun 10 08:15:13 2018 Thread-1 锁B Sun Jun 10 08:15:16 2018 Thread-1 锁B Sun Jun 10 08:15:16 2018 Thread-2 锁A Sun Jun 10 08:15:16 2018 ... 下面就卡死在这里
3、上面代码的分析
- 启动5个线程,当执行
run
方法的时候线程Thread-1
首先抢到A锁,线程Thread-1
继续执行,拿到B锁,但是A锁还是没释放出来,直到方法func1
全部执行完成,A、B锁才会全部释放出来。 - 当方法
func1
执行完后才会进行方法func2
,func2
先获取B锁,获取到了B锁后注意:B锁还没释放先休眠了3s. - 当
func2
进入休眠状态,pytyhon
不会让程序休息的,会去切换到别的线程上(进行第二个线程),进入线程Thread-2
中执行方法func1
,获取了锁A, - 这个时候线程二要继续获取B锁,可是B锁在线程一种还没被释放出来,线程一休眠3秒后,要获取锁A,可是锁A已经被线程二占用还没释放出来。
- 上面低四点中,因为两把锁都在对方手上,没被释放出来,都在等待对方先释放,就会卡死在这里。这就是所谓的死锁
- 启动5个线程,当执行
三、python
中递归锁
为了支持在同一线程中多次请求同一资源,造成死锁的现象,python
提供了"可重入锁":threading.RLock
。RLock
内部维护着一个Lock
和一个counter
(计数器)变量,counter
记录了acquire
的次数,从而使得资源可以被多次acquire
。直到一个线程所有的acquire
都被release
(counter=0
的时候),其他的线程才能获得资源。
1、实现代码
import threading import time class MyThread(threading.Thread): def func1(self): lock.acquire() print(self.name, '锁A', time.ctime()) lock.acquire() print(self.name, '锁B', time.ctime()) lock.release() lock.release() def func2(self): lock.acquire() print(self.name, '锁B', time.ctime()) time.sleep(3) lock.acquire() print(self.name, '锁A', time.ctime()) lock.release() lock.release() def run(self): self.func1() self.func2() # 创建一把递归锁 lock = threading.RLock() if __name__ == "__main__": for i in range(5): t = MyThread() t.start()
2、代码解答
在python
中的RLock
里面维护了一个计数器,当acquire
的时候就+1,当release
的时候就-1,如果计数器不为0的时候,别的线程就不糊执行。注意点:必须创建的是同一把锁,不能创建两把递归锁来锁