前端进阶之旅前端进阶之旅
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
  • 基础篇HTML/CSS/JS 打底
  • 进阶篇原理与工程化
  • 高频篇面试最常问的那批
  • 精选篇按模块收敛的总结
  • 手写篇常考代码手写实现
  • 面经篇真实面试问题复盘
  • AI 篇NEWAI 时代的前端考点
  • 历年面经NEW按年份追踪真实考点
  • 每日一题每天一道,攒手感
  • 专项自测100 题快速查漏
  • 小程序题库小程序专项刷题
  • 算法题库NEW在线编码即时判题
  • 知识卡片NEW碎片时间过考点
  • 面试题大全常见问题解析
  • AI 答疑NEW随时提问,即时解析
  • AI 模拟面试NEW模拟真实面试 + 报告
  • AI 定制路线NEW按你的简历现排
  • AI 知识地图NEW串起全站知识点
  • 原理篇React / Vue 源码拆解
  • HTTP从报文一路讲到 HTTPS
  • 浏览器渲染、事件循环、进程
  • 计算机基础Linux、网络、操作系统
  • 设计模式23 种模式怎么用
  • Node学习指南从环境搭建到服务端
  • NPM工作流script、依赖与发布
  • Docker容器化部署上手
  • Canvas图形与动画实战
  • 前端系统进阶学习大型项目工程化
  • 前端综合文章长期沉淀的实践文
  • 思维导图知识点全景图
  • 学习路线按图索骥不跑偏
  • AI 热点NEWAI 每日动态
  • 公众号动态公众号历史文章
  • 博客动态站长的技术博客
  • 开发者导航常用工具与文档站
首页程序员面试题库多 Agent 共享状态并发写冲突处理
AIAI Agent多 Agent 协作

多个 Agent 并发更新共享状态,怎样避免旧结果覆盖新决策?

并发写入的关键不是让所有 Agent 都读到状态,而是让每次提交证明自己仍基于有效版本。

前端进阶之旅 · 一题精讲更新于 2026.09.06
AI Agent#多 Agent 协作#多 Agent#并发编程
先看核心答案读代码示例
理解线索

一次提交需要哪些证据

  1. 读取版本知道决策依据是哪一版状态
  2. 原子提交只有版本仍符合预期才接受修改
  3. 冲突恢复基于新状态重新计算是否还有必要写入

示例只模拟单进程同步提交;真正的跨进程系统需要数据库或其他共享存储提供原子保证。

核心回答

先记住这个答案

可以为共享记录维护版本号,提交时携带读取到的预期版本,由存储层原子检查并更新;版本不匹配时拒绝旧写入,再读取新状态决定重算、合并或放弃。不同 Agent 也可拥有不同字段或产物,减少竞争,只有最终决策由明确的协调者提交。不能用先查询版本、稍后无条件写入的两步操作假装原子控制。并发控制阻止的是过期提交,业务是否允许状态倒退、哪些字段可合并,以及旧 worker 是否仍有写入资格,还要另行定义。

  • 预期版本检查与写入必须在存储边界原子完成
  • 冲突后重新判断,不能只替换版本号重交旧值
  • 字段归属与状态转换规则减少无意义竞争

为什么最后写入者胜出会让决策回退

两个 Agent 同时读到任务待处理,一个完成审查写入通过,另一个依据旧信息写入需要更多输入。若只按请求抵达顺序覆盖,较晚的旧结论会抹掉较新的有效结果。时间戳也不能自动证明业务新旧,因为网络延迟与时钟偏差都可能影响顺序。

下面两个更新都基于版本一,只有先提交的结果被接受。同步函数内没有 await,因此在这个单进程例子里检查和修改不会被另一段 JavaScript 插入;这只是展示语义,不能直接复制成多副本服务的全局锁。

拒绝基于旧版本的第二次提交JavaScript
let record = { version: 1, status: 'pending' };
function commit(expectedVersion, status) {
  if (record.version !== expectedVersion) return false;
  record = { version: record.version + 1, status };
  return true;
}
const firstRead = record.version;
const secondRead = record.version;
console.log(commit(firstRead, 'approved'));
console.log(commit(secondRead, 'needs-info'));
console.log(record.version, record.status);
查看输出与解释
true
false
2 approved

第二个执行者携带版本一,但记录已变成版本二,因此提交失败。真实数据库可以采用带版本条件的 UPDATE 并检查受影响行数;多条记录的不变量还需要事务或更完整的协调设计。

冲突处理必须重新审查业务前提

收到版本冲突后,直接把 expectedVersion 改成最新数字再提交原始状态,会绕过最有价值的保护。正确做法是读取新值,判断原始任务是否仍成立、哪些输入已经变化,以及旧结果是否可以作为独立证据保留。

有些更新可以合并,例如按唯一标识追加不同审查发现;有些不能随意合并,例如批准与拒绝同一个发布。应为每类状态定义合并函数、字段所有者和合法转换,不能把所有对象都做浅合并,也不能假定数组拼接天然可交换且可去重。

跨进程提交还要考虑过期执行者

租约过期后调度器可能启动新 worker,而旧 worker 从暂停中恢复继续提交。除了记录版本,必要时还应携带任务执行代次,由提交端拒绝旧代次。锁过期并不意味着旧进程被物理停止,外部副作用同样需要边界保护。

对于多条记录一起更新的业务,单行版本检查不一定保护整体条件。应结合事务隔离、约束或单一提交者,测试并发冲突、进程恢复和重复消息。这里的目标是保持业务不变量,而不是让每一次竞争写入都必然成功。

回答前,多想一步

容易答错的地方

先读版本再普通 UPDATE 就是 CAS
这两步之间可能有另一个写入;预期版本必须进入实际更新条件,或由事务与锁提供相应保证,才能消除检查与使用之间的窗口。
所有冲突都能通过字段浅合并解决
字段可能表达互斥状态或共同约束,分别保留两份值会产生不可能的组合;合并需要基于业务语义,而不是对象形状。
试着用自己的话回答

面试官还会怎么问?

用时间戳代替整数版本可以吗?

可以设计其他并发令牌,但必须有可靠的唯一性与比较语义;客户端时间通常不适合作为唯一依据,存储层提供的不透明版本也很常见。

冲突次数很多说明乐观锁不适合吗?

可能意味着共享粒度过大或写入责任不清。先分离独立产物、缩短读取到提交的时间,再评估是否需要串行协调或其他策略。

版本号能防止重复发送外部消息吗?

只能保护它实际参与的提交边界。如果发送发生在状态更新之前或外部系统之外,还需要幂等键、事务消息或可核对的副作用记录。

从一道题,走向一组知识

把知识连起来

多 Agent 协作

多 Agent 协作该用共享黑板还是消息传递,两者怎么组合?

共享状态和消息需要不同的协作与一致性约定

多 Agent 协作

下游 Agent 交接任务失败了,应该由哪一层负责重试?

任务接管后需识别旧执行者的迟到结果

参考资料

  • PostgreSQL:Transaction Isolation

示例用于理解所注明的运行环境与边界;延伸学习可结合原文中的更多案例。

本题目录
  1. 先记住这个答案
  2. 为什么最后写入者胜出会让决策回退
  3. 冲突处理必须重新审查业务前提
  4. 跨进程提交还要考虑过期执行者
  5. 容易答错的地方
  6. 面试官还会怎么问
  7. 把知识连起来
读懂,再试着讲出来

先看核心答案,再读代码。最后展开追问,检查自己有没有遗漏边界。

试着回答追问
浏览全部面试题理解原理,也关注真实的使用场景。回到顶部 ↑