题目重点:解释竞态、锁与乐观版本,围绕项目证明不变量而非列工具。
题意与假设
这道练习题保留了面经中值得训练的核心约束,并将需要澄清的条件单独列出。现场拿到变体时,先和面试官确认这些条件。
- 项目并发问句未给固定语言;以共享计数、状态迁移与数据库版本为训练案例。
解题路线
- 列共享状态和不变量,再定位读写及需要原子的多步操作。race不仅是同时写,同步缺失还会造成可见性和顺序问题。
- 锁把需要一起变化的状态包住,统一加锁顺序避免死锁,锁内不做无预算网络I/O。细锁提高并行但增加协调和复杂度。
- 乐观版本读v、计算、条件写whereversion=v,失败重试;外部副作用不能在每次重试都执行,需幂等或事务/outbox。
- 容器线程安全只保证其合同,跨两个容器/键的业务不变量仍需协调。取消、超时与异常路径必须释放资源。
- 验证用可控调度、线性化历史和不变量,不只压测吞吐。性能观察锁等待、热点和P99,不能以CPU不高判定无瓶颈。
手动走一遍
余额10两个并发扣7,若都读10再写3可双花;条件扣减必须保证余额检查与扣款同原子域。读版本后HTTP发券、再CAS失败重试会重复发券,即使最终数据库正确。
规模与取舍
共享热点限制并行扩展;无锁不保证低延迟,重试成本随冲突率增长。报告正确性与吞吐/尾延迟分别验证。
易错点与追问
容易失分的边界
- volatile解决所有复合竞态。
- 乐观重试没有上限和幂等。
- 为了缩锁范围打破原子不变量。
继续深挖
- 如何定义线性化点?
- 跨服务状态迁移怎样建幂等合同?
