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

Node.js:如何实现简易Mutex机制规避竞态条件

解决Task类的并发竞态问题

你的核心问题是原实现中_busy布尔值的检查与锁定操作无法可靠保证排他性,在多异步回调并发触发run时,会出现多个调用绕过检查的情况。以下是两个无需依赖第三方库的简单解决方案:

方案一:用Promise跟踪执行状态

通过维护当前执行任务的Promise实例替代布尔锁,确保检查与锁定的原子性:

class Task {
    _cb;
    _currentTask = null; // 跟踪当前正在执行的任务

    constructor(cb) {
        this._cb = cb;
    }

    async run(params = []) {
        // 已有任务在执行时直接返回
        if (this._currentTask) {
            return;
        }

        try {
            // 创建任务Promise并标记锁定状态
            this._currentTask = (async () => {
                await this._cb(...params);
            })();
            await this._currentTask;
        } catch (err) {
            await someLoggingRoutine();
        } finally {
            // 任务完成后解锁
            this._currentTask = null;
        }
    }
}

该方案利用Promise赋值的同步原子性,一旦第一个调用设置了_currentTask,后续所有调用都会直接返回,彻底避免竞态。

方案二:优化布尔锁的原子性逻辑

如果偏好布尔值锁的方式,可调整逻辑确保检查与锁定的连续性:

class Task {
    _cb;
    _locked = false;

    constructor(cb) {
        this._cb = cb;
    }

    async run(params = []) {
        // 原子性检查并锁定:通过检查后立即标记为锁定
        if (this._locked) return;
        this._locked = true;

        try {
            await this._cb(...params);
        } catch (err) {
            await someLoggingRoutine();
        } finally {
            // 无论成功失败都必须解锁,避免永久锁定
            this._locked = false;
        }
    }
}

原方案失效原因

原代码中Race condition!日志出现的本质是:当多个run调用的同步逻辑在同一事件循环周期内连续执行时,第一个调用还未完成this._busy = true的赋值,第二个调用就已经通过了if (this._busy)检查——这是因为异步回调的任务调度特性,导致多个同步逻辑块被快速连续执行,突破了布尔锁的防护。

上述两个方案都能确保同一时间只有一个run调用执行目标回调,其余调用直接返回,完全满足你的排他执行需求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 02:40:18