多线程-3-并发意外串行-lock

现象:没有使用lock却没有发生账户取钱bug

实例代码:

from threading import Lock
import threading
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
# logger.setLevel(logging.INFO)
import time
class Account:
    def __init__(self,name,money):
        self.name = name
        self.money = money

class GetMoney(threading.Thread):
    def __init__(
    self,
    money:float,
    account:Account):
        super().__init__()
        self.num = money
        self.account = account
    def run(self) -> float:
        time.sleep(1)
        
        if self.num > self.account.money:
            logger.info(f"余额不足,当前余额为{self.account.money}")
            return
        self.account.money -= self.num
        logger.info(f"余额为{self.account.money}")
        return self.account


if __name__ == "__main__":
    account = Account("cc",1000)
    you = GetMoney(800,account)
    your_wife = GetMoney(800,account)
    you.start()
    your_wife.start()
    you.join()
    your_wife.join()

运行结果:

INFO:__main__:余额为200
INFO:__main__:余额不足,当前余额为200

分析:

  1. 没有使用锁机制,所以理论上存在竞态条件(race condition),多个线程可能同时核验账户足够,导致余额变为负数
  2. python线程调度由操作系统GIL共同影响,GIL确保在同一时刻仅能运行一个thread,这可能导致并发意外串行执行,但是这依赖于运气,系统负载、CPU核心数等因素并不可靠
  3. 竞态条件是间歇性的,取决于运行环境。生产代码中,这种问题可能在压力测试或实际部署时才暴露,导致数据不一致(如银行余额负数)。
  4. self.account.money -= self.num 不是原子操作:它涉及读取 money 、减法、写入。如果两个线程同时读取同一个值(例如 1000),都减 800,都写入,最终可能变成 200 而不是预期(第一个扣到 200,第二个不扣)。但没有锁,写入可能重叠,导致错误。

改进:加锁

class GetMoney(threading.Thread):
    def __init__(
    self,
    money:float,
    account:Account):
        super().__init__()
        self.num = money
        self.account = account
    def run(self) -> float:
        time.sleep(1)
        with Lock():
            if self.num > self.account.money:
                logger.info(f"余额不足,当前余额为{self.account.money}")
                return
            self.account.money -= self.num
        logger.info(f"余额为{self.account.money}")
        return self.account

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值