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

Goroutine变量赋值是否需同步?ErrGroup场景锁与内存可见性分析

回答:必须使用锁来保证内存可见性

你确实需要保留锁来保护这些赋值操作,核心原因不是互斥(毕竟两个子goroutine分别操作one和two,完全不会产生竞争),而是内存可见性——这也是你提到《Java Concurrency In Practice》里的核心点:

锁不仅用于互斥,还关乎内存可见性。为确保所有线程都能看到共享可变变量的最新值,读写线程必须在同一个锁上同步。

具体到你的Go代码场景:

这里存在三个goroutine:父goroutine和两个子goroutine。虽然errgroup.Wait()会阻塞父goroutine,直到两个子goroutine都执行完毕,但Go的内存模型不会自动保证子goroutine对共享变量的写入,在父goroutine中可见——除非通过同步原语(比如锁、channel操作)建立明确的happens-before关系。

你的代码里的锁完美解决了这个问题:

  • 子goroutine在赋值one/two后调用mu.Unlock()
  • 父goroutine在读取前调用mu.Lock()

根据Go内存模型,Unlock操作happens before后续同一个锁的Lock操作,这就确保了父goroutine能看到子goroutine对one和two的最新赋值。

如果省略锁会发生什么?

如果去掉所有锁,即使g.Wait()等待子goroutine完成,父goroutine执行performAction(one, two)时,可能会读取到one或two的零值(nil)。这是因为CPU缓存的特性:子goroutine的赋值可能只存在于它所在CPU的本地缓存中,没有同步到主存;而父goroutine读取的是自己CPU缓存里的旧值,完全看不到子goroutine的更新。

总结

哪怕没有互斥竞争的需求,只要涉及到跨goroutine的共享变量读写,就需要用同步原语(比如这里的锁)来保证内存可见性,确保所有goroutine看到的变量值是一致的。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 04:37:19