Skip to content

竞态条件(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)。

进一步阅读

竞态条件是并发的“第一坑”,理解它会帮你理解死锁、原子性、事务等概念。

CC-BY 4.0 Licensed