Appearance
竞态条件(Race Condition)
当多个任务同时读写同一份共享状态时,结果取决于“谁先谁后”,这就叫竞态条件。
原子性与临界区
count = count + 1 看起来是一句,但实际包含三个步骤:读取、计算、写回。只要这三个步骤之间可以被打断,就可能出错。
必须连续执行、不能被打断的代码段,叫做临界区。
javascript
let count = 0;
async function inc() {
let current = count;
await Promise.resolve();
count = current + 1;
}
Promise.all([inc(), inc()]).then(() => console.log(count)); // 可能是 1常见后果
- 丢失更新:两个操作互相覆盖。
- 结果不稳定:同样输入多次运行结果不同。
- 难以复现:只有在特定时序下才出现。
常见对策
- 锁/互斥:同一时间只允许一个任务进入临界区。
- 队列化:把操作排队顺序执行。
- 不可变数据:避免修改共享对象。
- 消息传递:不共享内存,只传递消息(如 Worker)。
进一步阅读
竞态条件是并发的“第一坑”,理解它会帮你理解死锁、原子性、事务等概念。