Python3之并发(四)---线程锁

一、线程锁

保证多线程数据的一致性,对锁内的资源进行锁定,同一时间只能有一个线程来修改共享的数据
多个线程同时加了同一个锁对象时,先获取到锁的线程会继续运行,未获取到锁的线程会处于堵塞状态,直到前面的线程释放锁,重新获取到锁才会往下运行

类型

threading.Lock
基本锁对象,每次只能获取一次,其他锁请求需要等锁释放后才能获取
若想对同一线程多次锁,必须等前面的锁释放,否则会变成死锁

threading.RLock
可重入锁,同一个线程中可以多次获取,也可以多次释放,但是获取和释放的次数必须要一致

锁对象的方法

Lock.acquire(blocking=True, timeout=-1)
获取锁,获取成功返回 True,否则返回 False
blocking: 默认True,堵塞没有获取到锁的线程
timeout: blocking=True时,没有获取到锁的线程的堵塞超时时间,默认-1,无限制等待;blocking=Flase时,禁止设置timeout

Lock.release()
释放锁,可以从任何线程调用此函数,没有返回值
对已解锁的锁使用该方法引发 RuntimeError 异常

示例

不加锁时

取钱两次之后,余额是负数

import threading, time

#账户类
class Account:
    def __init__(self, account_no, balance):
        #账户编号和账户余额
        self.account_no = account_no
        self.balance = balancedef getBlance(self):
        return self.balance
    
    #提取现金方法
    def draw(self, draw_amount):
        if self.balance >= draw_amount:
            print(threading.current_thread().name+'	取钱成功!吐出钞票:'+str(draw_amount))
            time.sleep(1)
            self.balance -= draw_amount
            print(threading.current_thread().name+'操作之后	余额为:'+str(self.balance))
        else:
            print(threading.current_thread().name+'	取钱失败!余额不足!	当前余额为:'+str(self.balance))

acct = Account('986623', 1500)
thread_1 =threading.Thread(target=acct.draw, args=(800,), name='thread_1')
thread_2 =threading.Thread(target=acct.draw, args=(900,), name='thread_2')
thread_1.start()
thread_2.start()

加锁时

#账户类
class Account:
    def __init__(self, account_no, balance):
        #账户编号和账户余额
        self.account_no = account_no
        self.balance = balance

        self.lock = threading.RLock()
    
    def getBlance(self):
        return self.balance
    
    #提取现金方法
    def draw(self, draw_amount):
        with self.lock:
            if self.balance >= draw_amount:
                print(threading.current_thread().name+'	取钱成功!吐出钞票:'+str(draw_amount))
                time.sleep(1)
                self.balance -= draw_amount
                print(threading.current_thread().name+'操作之后	余额为:'+str(self.balance))
            else:
                print(threading.current_thread().name+'	取钱失败!余额不足!	当前余额为:'+str(self.balance))

acct = Account('986623', 1500)
thread_1 =threading.Thread(target=acct.draw, args=(800,), name='thread_1')
thread_2 =threading.Thread(target=acct.draw, args=(900,), name='thread_2')
thread_1.start()
thread_2.start()

死锁

当两个线程互相等待对方释放各自要加锁的锁对象时(即两个线程占用着各自将要加锁的锁对象),就会产生死锁
出现死锁时,程序会出现僵持的状态并且无法继续执行下去

避免死锁问题

避免多次锁定: 尽量避免同一个线程对多个锁对象进行锁定
具有相同的加锁顺序: 多个线程对多个锁对象加锁时,应该保证它们以相同的顺序请求加锁
使用定时锁: 程序在调用acquire()方法加锁时可以指定timeout参数,超时会自动释放锁
死锁检测: 依靠算法机制来实现的死锁预防机制
原文地址:https://www.cnblogs.com/gudanaimei/p/14408831.html