首页 > 编程语言 >一个并发编程中线程同步和同步锁的问题

一个并发编程中线程同步和同步锁的问题

时间:2023-01-12 17:36:40浏览次数:37  
标签:__ draw 同步 threading self 编程 account 并发 balance

(一个并发编程中线程同步和同步锁的问题)

1. 线程安全问题

  • 经典问题——银行取钱问题里面的核心问题
    • (1)用户输入账户、密码并判断
    • (2)输入取款金额
    • (3)判断余额与取款金额孰多孰少
    • (4)如果余额大于取款金额则取款成功;否则失败
  • 若是代码如下:
import threading
import time


class Account:
    # 初始化构造器
    def __init__(self, account_no, balance):
        # 封装账户编号和账户余额两个成员变量
        self.account_no = account_no
        self.balance = balance
   
    # 提供模拟取钱的draw方法来完成取钱操作
    def draw(self, account, draw_amount):
        # 账户余额必须大于取钱数目       
        if account.balance >= draw_amount:   
            # 取出钞票的数额
            print(threading.current_thread().name + " 取钱成功!吐出钞票:" + str(draw_amount))
            # 模拟其它线程切换进来,注释掉也有机会出现
            time.sleep(0.0000000000000000000001)
            # 修改余额
            account.balance -= draw_amount
            print("余额为:" + str(account.balance))
        else:
            print(threading.current_thread().name + " 取钱失败,余额不足!")


if __name__ == '__main__':
    # create a Account
    acct = Account("1234567", 1000)
    threading.Thread(target=acct.draw, args=(acct, 800)).start()
    # 第一个进行的时候,第二个也有可能抢进来
    threading.Thread(target=acct.draw, args=(acct, 800)).start()
  • 会出现如下问题: 在这里插入图片描述
  • 所以用同步锁的方法,解决。

2. 同步锁(Lock)

import threading
import time

class Account:
    # 初始化构造器
    def __init__(self, account_no, balance):
        # 封装账户编号和账户余额两个成员变量
        self.account_no = account_no
        self._balance = balance
        self.lock = threading.RLock()
    # 因为账户余额不允许随便修改,所以只为self._balance提供getter方法    
    def getBalance(self):
        return self._balance
    #提供一个线程安全的draw方法来完成取钱操作
    def draw(self, account, draw_amount):
        # 加锁
        self.lock.acquire()
        try:
            if account._balance >= draw_amount:   
                # 这里在_balance是指私有变量,只能由类对象和子类对象修改
                # 取出钞票的数额
                print(threading.current_thread().name + " 取钱成功!吐出钞票:" + str(draw_amount))
                time.sleep(0.00000000000001)

                # 修改余额
                account._balance -= draw_amount
                print("余额为:" + str(account._balance))
            else:
                print(threading.current_thread().name + " 取钱失败,余额不足!")
        finally:
            # 修改完成,释放锁
            self.lock.release()


if __name__ == '__main__':
    # create a Account
    acct = Account("1234567", 1000)
    threading.Thread(target=acct.draw, args=(acct, 800)).start()
    # 第一个完成不了,第二个就没法完成
    threading.Thread(target=acct.draw, args=(acct, 800)).start()
  • 上面加锁之后,同一个类对象的加锁的方法只由一个线程完成,解锁之后,其它线程才可以使用。

标签:__,draw,同步,threading,self,编程,account,并发,balance
From: https://blog.51cto.com/u_15930659/6004526

相关文章