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

Go使用RWMutex操作map出现重复写入问题及方案咨询

问题根因

你遇到的重复写入问题本质是读写锁释放后的判断存在竞态条件:两个goroutine都在持有读锁的阶段读到了空值,释放读锁后用已经过期的旧值做判断,此时都满足len(t) <= 0的条件进入if代码块,后续加写锁只能保证写入操作的互斥,没法阻止已经进入if块的goroutine执行写入逻辑,所以会出现两次写入的情况。


问题2:上述代码是不是Go多goroutine操作map的正确实现?

不是。
RWMutex能保证的只有持有锁期间的操作是线程安全的,你将「值是否存在」的判断逻辑放在了读锁释放之后,判断依据的旧值和map当前的实际状态已经没有一致性保障,虽然写入时加了Lock不会出现map并发写入的panic,但逻辑上存在竞态,不符合业务预期。


问题1:有没有方法保证仅一个goroutine执行写入操作?

可以用**双重检查锁定(Double-Checked Locking)**的方案解决,核心逻辑是拿到写锁之后,再次读取map的当前状态做二次判断,避免重复写入:

func (r *RLockAndLockStruct) RLockAndLockTest(value string, goroutine string) string {
    r.mu.RLock()
    fmt.Printf("%sRLock\n", goroutine)
    t := r.mapEx[value]
    r.mu.RUnlock()
    fmt.Printf("%sRUnlock\n", goroutine)
    if len(t) <= 0 {
        time.Sleep(500 * time.Millisecond)
        r.mu.Lock()
        // 加写锁后二次检查,确认当前map确实没有对应值再写入
        t = r.mapEx[value]
        if len(t) <= 0 {
            fmt.Printf("%sLock\n", goroutine)
            r.mapEx[value] = value
        }
        r.mu.Unlock()
        fmt.Printf("%sUnlock\n", goroutine)
        if len(t) <= 0 {
            return value
        }
    }
    return t
}

这个写法保留了原实现读多写少场景下的性能优势,仅在读未命中时才会加写锁,二次检查保证只有第一个拿到写锁的goroutine会执行写入,后续进入if块的goroutine拿到写锁后会发现已经有值,直接跳过写入逻辑。

如果你的场景是全局仅初始化一次这个key的值,也可以用sync.Once实现,写法更简洁,天然保证执行次数唯一:

type RLockAndLockStruct struct {
    mu sync.RWMutex
    initOnce sync.Once
    mapEx map[string]string
}

func (r *RLockAndLockStruct) RLockAndLockTest(value string, goroutine string) string {
    r.mu.RLock()
    t := r.mapEx[value]
    r.mu.RUnlock()
    if len(t) > 0 {
        return t
    }
    // 保证匿名函数仅执行一次
    r.initOnce.Do(func() {
        r.mu.Lock()
        defer r.mu.Unlock()
        // 兼容多key场景的二次检查,如果是单key固定初始化可以去掉
        if len(r.mapEx[value]) <= 0 {
            r.mapEx[value] = value
        }
    })
    // 读取写入后的值
    r.mu.RLock()
    t = r.mapEx[value]
    r.mu.RUnlock()
    return t
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 03:27:00