You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python线程实现银行账户存取款:如何避免余额为负?

银行账户线程安全存取款问题解决

原代码的问题在哪?

原代码的锁只护住了余额修改的步骤,但判断余额是否为负的操作在锁外面,这就导致了竞态问题:比如取款线程看到余额≥0,刚要执行取款,存款线程突然插进来把余额取成负数,取款线程接着执行就会让余额变负。而且没有办法让取款线程在余额不够时停下来等存款。

解决办法:用Condition条件变量

得用threading.Condition代替单纯的Lock,它不仅能实现互斥,还能让线程在条件不满足时进入等待,等其他线程触发信号再继续。

修改后的代码

import threading

balance = 0
nb_transaction = 999999
counter = 0
# 用Condition,自带锁功能
money_cond = threading.Condition()

def transaction(nb_transaction, n):
    global balance
    global counter
    for _ in range(nb_transaction):
        with money_cond:
            # 取款操作时,必须等余额足够才能继续
            if n == -1:
                # 用while循环防止虚假唤醒,确保条件真的满足了才执行
                while balance <= 0:
                    money_cond.wait()
            # 执行存/取款操作
            balance += n
            # 操作完通知所有等待的线程,让它们重新检查条件
            money_cond.notify_all()

t1 = threading.Thread(target=transaction, args=(nb_transaction, 1))
t2 = threading.Thread(target=transaction, args=(nb_transaction, -1))

t1.start()
t2.start()

t1.join()
t2.join()

print(counter)  # 最终为0,不会出现余额为负的情况
print(balance)  # 最终为0,存和取次数完全一致

关键逻辑说明

  • Condition的使用:用with语句自动管理锁的获取和释放,不用手动调用acquire()和release(),代码更简洁。
  • 取款等待逻辑:取款线程发现余额不够时,调用wait()释放锁并进入等待状态,直到存款线程完成操作后调用notify_all()唤醒它。用while循环而不是if,是因为线程可能被虚假唤醒(没等到通知就醒了),必须重新检查余额是否足够。
  • 通知机制:每次存/取款完成后,唤醒所有等待的线程,让它们重新判断是否可以执行自己的操作。
  • 最终余额保证为0:因为存和取的次数完全相同,而且取款只有在余额足够时才会执行,所以最后余额必然是0,counter也会是0,不会出现余额为负的情况。

为啥原锁解决不了问题?

原代码里判断余额的操作在锁外面,多个线程可以同时读余额的值,判断和修改不是原子操作。比如线程2读到余额是1,刚要执行取款,线程1抢过来把余额改成0,线程2还是会执行取款,结果余额就变负了。只有把判断和修改都放到锁的保护范围内,再用Condition处理等待,才能彻底避免这个问题。

内容的提问来源于stack exchange,提问作者user398843

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 21:43:29