1. 为什么需要线程锁?
多个线程对同一个数据进行修改时, 可能会出现不可预料的情况.
2. 如何实现线程锁?
# 1. 实例化一个锁对象;
lock = threading.Lock()
# 2. 操作变量之前进行加锁
lock.acquire()
# 3. 操作变量之后进行解锁
lock.release()
python多线程是并发执行,有可能会出现错误
并发: 交替执行
并行: 同时执行
多线程和多进程最大的不同在于,多进程中,同一个变量,各自有一份拷贝存在于每个进程中,互不影响,而多线程中,所有变量都由所有线程共享,所以,任何一个变量都可以被任何一个线程修改,因此,线程之间共享数据最大的危险在于多个线程同时改一个变量,把内容给改乱了。
锁的好处就是确保了某段关键代码只能由一个线程从头到尾完整地执行,坏处当然也很多,首先是阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了。 其次,由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁,导致多个线程全部挂起,既不能执行,也无法结束,只能靠
操作系统强制终止。
先看一个没有加线程锁错误的存钱取钱的例子:
import threading
def add():
global money
for i in range(1000000):
money += 1
def reduce():
global money
for i in range(1000000):
money -=1
if __name__ == '__main__':
money = 0
# lock = threading.Lock()
t1 = threading.Thread(target=add)
t2 = threading.Thread(target=reduce)
t1.start()
t2.start()
t1.join()
t2.join()
print('当前金额:',money)
在计算量比较大时容易出现错误,存1000000取1000000当前金额应该是0.结果运行很多次却是负数明显错误了。
加上线程锁
方法一:threading.Thread
import threading
# 银行存钱和取钱
def add(lock):
global money # 生命money为全局变量
for i in range(1000000):
# 2. 操作变量之前进行加锁
lock.acquire()
money += 1 # money; money+1; money=money+1;
# 3. 操作变量之后进行解锁
lock.release()
def reduce(lock):
global money
for i in range(1000000):
# 2. 操作变量之前进行加锁
lock.acquire()
money -= 1
# 3. 操作变量之后进行解锁
lock.release()
if __name__ == '__main__':
money = 0
# 1. 实例化一个锁对象;
lock = threading.Lock()
t1 = threading.Thread(target=add, args=(lock,))
t2 = threading.Thread(target=reduce, args=(lock,))
t1.start()
t2.start()
t1.join()
t2.join()
print("当前金额:", money)
无论运行多少次结果都是0
方法二:
重写run方法
import threading
# 银行存钱和取钱
class AddThread(threading.Thread):
def __init__(self,lock):
super(AddThread,self).__init__()
self.lock = lock
def run(self):
global money # 生命money为全局变量
for i in range(1000000):
# 2. 操作变量之前进行加锁
self.lock.acquire()
money += 1 # money; money+1; money=money+1;
# 3. 操作变量之后进行解锁
self.lock.release()
class ReduceThread(threading.Thread):
def __init__(self,lock):
super(ReduceThread,self).__init__()
self.lock = lock
def run(self):
global money
for i in range(1000000):
# 2. 操作变量之前进行加锁
self.lock.acquire()
money -= 1
# 3. 操作变量之后进行解锁
self.lock.release()
if __name__ == '__main__':
money = 0
# 1. 实例化一个锁对象;
lock = threading.Lock()
# 重写run方法通过新写的类AddThread、ReduceThread实例化对象
# t1 = threading.Thread(target=add, args=(lock,))
# t2 = threading.Thread(target=reduce, args=(lock,))
t1 = AddThread(lock)
t2 = ReduceThread(lock)
t1.start()
t2.start()
t1.join()
t2.join()
print("当前金额:", money)