threading.Thread子类临界区问题:仅run写入的字段只读访问是否要加锁
问题解答
这个问题的核心取决于你对数据一致性的要求、以及_field字段的更新逻辑,分两种场景判断:
无需加锁的唯一情况
如果同时满足以下两个条件,可以不加锁:
run方法对self._field的更新是单次完整赋值的原子操作:比如self._field = 接口返回的字符串/数字/完整字典/完整列表,这类操作在CPython中受GIL保护,是不可拆分的原子操作,不会出现读取到半更新状态的「数据撕裂」问题- 你可以接受
get_field返回任意时刻的新旧值,没有严格的「必须读到最新值」「读写时序严格一致」要求
注意:这种写法的风险是受CPU缓存影响,读线程可能长时间读取到旧的
_field值,且如果后续扩展写入逻辑很容易引入并发BUG。
必须加锁的情况
只要符合以下任意一条,就必须加锁:
run方法对self._field的更新是原地修改操作:比如self._field["key"] = 新值(原地改字典)、self._field.append(元素)(原地改列表)、分多步修改_field的属性,这类操作不是原子的,读线程可能拿到更新一半的不一致数据- 你对数据可见性有要求:加锁会强制刷新CPU缓存,保证读线程能拿到写入完成后的最新值
- 后续可能扩展代码:如果未来可能新增其他修改
_field的方法,提前加锁可以避免后续出现难以排查的并发问题
加锁后的实现示例
import threading class Client(threading.Thread): def __init__(self): super().__init__() self._field = None self._lock = threading.Lock() def run(self): # 连接REST API获取最新数据 new_field = request_api(xxx) # 写入时加锁 with self._lock: self._field = new_field def get_field(self): # 读取时加锁 with self._lock: return self._field
内容的提问来源于stack exchange,提问作者Sara1209
相关产品推荐
相关产品推荐

