zoukankan      html  css  js  c++  java
  • 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参数,超时会自动释放锁
    死锁检测: 依靠算法机制来实现的死锁预防机制
  • 相关阅读:
    纯js实现字符串formate方法
    C#实现json压缩和格式化
    简单的前端校验框架实现
    快速拷贝文件
    0012 移除元素
    0011 删除链表的倒数第N个节点
    0010 最长公共前缀
    0009 合并两个有序链表
    0008 合并K个排序链表
    0007 回文数
  • 原文地址:https://www.cnblogs.com/gudanaimei/p/14408831.html
Copyright © 2011-2022 走看看