You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java Synchronized块在Node.js中的等价实现 限制方法仅单Promise执行

Node.js 异步方法互斥锁实现方案

核心思路

你的问题核心是异步方法的执行竞态:虽然Node.js是单线程运行,但await关键字会让出事件循环,导致校验和插入的间隙可以响应其他方法调用,进而触发数据一致性问题。我们只需要给目标方法加执行锁,保证同一时间只有一个调用能走完「数据库校验+插入」的完整流程即可。

代码实现

class YourService {
  // 私有锁标记:标记当前方法是否正在运行
  #isMyMethodLocked = false;
  // 等待队列:存储后续并发调用的待执行任务
  #myMethodQueue: Array<() => void> = [];

  async myMethod(obj: MyObj): Promise<MyObj> {
    // 已有任务在运行,将当前调用加入等待队列
    if (this.#isMyMethodLocked) {
      return new Promise((resolve, reject) => {
        this.#myMethodQueue.push(async () => {
          try {
            const result = await this.#runMyMethodLogic(obj);
            resolve(result);
          } catch (err) {
            reject(err);
          }
        });
      });
    }

    // 无运行任务,直接上锁执行
    this.#isMyMethodLocked = true;
    try {
      return await this.#runMyMethodLogic(obj);
    } finally {
      // 当前任务执行完成,解锁并处理队列中下一个任务
      this.#isMyMethodLocked = false;
      const nextTask = this.#myMethodQueue.shift();
      nextTask?.();
    }
  }

  // 抽离原方法的核心业务逻辑
  async #runMyMethodLogic(obj: MyObj): Promise<MyObj> {
    const canInsert = await this.DbChecks();
    if (canInsert === true) {
      return this.insert(obj);
    }
    // 补充原逻辑缺失的分支返回,可根据业务需求调整为返回null或自定义错误
    throw new Error('当前不允许执行插入操作');
  }
}

方案说明

  • 完全保证核心逻辑同一时间只有一个实例在运行,彻底避免校验和插入的间隙被其他调用修改数据库的问题
  • 并发调用会按触发顺序进入队列排队,前一个调用执行完成(无论成功失败)后才会执行下一个
  • 如果业务不需要排队等待,而是要直接拒绝并发调用,可以简化逻辑:检测到锁被占用时直接抛出「并发调用受限」的错误即可

可选优化

如果互斥不需要全局生效,只需要针对特定维度(比如同一个用户、同一条数据ID)生效,可以把锁改成Map结构,key为对应维度的标识,能有效缩小锁粒度、提升并发性能。

内容的提问来源于stack exchange,提问作者Litel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.10 15:03:01