直接用 int 做计数器在多线程下会出错,因为 += 操作非原子,涉及读取、计算、写回三步,可能被其他线程打断,导致竞态条件和结果小于预期。

为什么直接用 int 做计数器在多线程下会出错?
因为 += 操作不是原子的:读取当前值 → 计算新值 → 写回内存,三步之间可能被其他线程打断。两个线程同时执行 counter += 1,最终只加了 1 而不是 2,这是典型的竞态条件。现象通常是计数结果小于预期,且每次运行结果不一致。
常见错误写法:
counter = 0<br>def increment():<br> global counter<br> counter += 1 # ❌ 非原子操作
用 threading.Lock 实现最稳妥的手动同步
这是最直观、可控性最强的方式,适合需要自定义逻辑(比如带条件更新)或兼容旧 Python 版本的场景。
- 必须在所有读写操作前获取锁,包括
get()、increment()、reset() - 推荐用
with lock:语法,避免忘记释放锁导致死锁 - 不要把锁对象暴露给外部调用者,否则可能被误用
示例:
Python 3.14.2是Python编程语言在2025年12月5日发布的稳定版本,属于3.14系列的第二个维护更新。该版本包含了18项修复,重点解决了多进程、数据类及正则表达式等模块的回归问题,并修复了CVE-2025-12084等安全漏洞。此版本标志着自由线程模式(移除GIL)正式获得官方支持,是Python发展的重要里程碑。
import threading<br><br>class ThreadSafeCounter:<br> def __init__(self):<br> self._value = 0<br> self._lock = threading.Lock()<br><br> def increment(self, delta=1):<br> with self._lock:<br> self._value += delta<br><br> def get(self):<br> with self._lock:<br> return self._value
用 threading.AtomicInteger?不存在 —— 别信网上过时资料
Python 标准库中没有 AtomicInteger 类(那是 Java 的)。有人尝试用 ctypes 或 _thread 模拟原子操作,但极易出错,且 CPython 的 GIL 并不能保证用户级整数操作的原子性(GIL 只保护解释器状态,不保护你的变量)。
所以别绕弯子,老实用 threading.Lock 或下面这个更轻量的选择:
-
threading.local()只解决“每个线程独立副本”问题,不适用于共享计数 -
queue.Queue过重,仅适合生产者-消费者模式,不是计数器替代方案 - 第三方包如
atomic已多年未维护,不建议引入
性能敏感时考虑 threading.RLock 还是 Lock?
绝大多数计数器场景用 threading.Lock 就够了。RLock 允许同一线程重复 acquire,但带来额外开销,且计数器通常不需要递归调用自身。
- 如果计数器方法之间有嵌套调用(比如
increment()内部又调get()),才需RLock - 否则一律用
Lock,它更快、更简单 - 实测在 100 万次操作下,
Lock比RLock快约 15%~20%
真正容易被忽略的是:锁粒度。别为了“看起来高级”而把整个对象方法都锁住,而是只锁真正共享的字段读写段——像上面示例那样,锁只包裹 self._value += delta 这一行,而不是整个函数体。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










