

新闻资讯
技术学院该用 sync.Mutex 而不是 sync.RWMutex 的情况是写操作频繁或读写比例接近 1:1 甚至写更多时,因其无状态切换开销、无写饥饿风险、加解锁路径最短,且避免 RWMutex 在写多时的排队放大与死锁风险。
sync.Mutex 而不是 sync.RWMutex
当你需要「写操作频繁」或「读写比例接近 1:1 甚至写更多」时,sync.Mutex 更简单、更安全。它没有读写状态切换开销,也没有写饥饿风险,加锁/解锁路径最短。
bank.Account.Transfer、连接池分配器、状态机状态变更(如 isClosed 标志位更新)RWMutex 反而更慢:每次 RLock 都要检查是否有等待中的写锁,而写锁又会阻塞所有新读请求,造成排队放大if x == 0 { x++ }),强行用 RWMutex 容易掉进死锁坑——后面会细说RLock 和 Lock 混用时最常触发的死锁怎么避最典型的错误是在持有 RLock 的 goroutine 里直接调用 Lock:
func (c *Counter) IncrementIfZero() {
c.mu.RLock()
defer c.mu.RUnlock()
if c.value == 0 {
c.mu.Lock() // ⚠️ 死锁:自己占着读锁,又等自己释放读锁才能拿写锁
c.value++
c.mu.Unlock()
}
}
RWMutex 不允许同一线程「读锁未放就抢写锁」,底层会一直阻塞直到所有读锁释放(包括当前 goroutine 持有的那个)RWMutex 允许 A goroutine 加读锁、B goroutine 解读锁,但混用极
易出错,不建议RWMutex 真的比 Mutex 快多少实测数据(Go 1.22, 8 核)显示:当读操作占比 ≥ 70%,RWMutex 的吞吐量可高出 Mutex 2–4 倍;但一旦读占比降到 40% 以下,两者性能基本持平,甚至 RWMutex 因额外状态管理略慢。
Mutex 更轻量RWMutex 内部其实嵌套了一个 sync.Mutex(用于保护写锁逻辑),所以它不是零成本的「升级版」Go 的 sync.Mutex 和 sync.RWMutex 都是值类型,零值可用,但「首次使用后禁止拷贝」是一条铁律。很多 bug 来自结构体字段被浅拷贝或作为函数参数传值。
mu(不是 mutex)或带后缀如 dataMu,这是 Go 社区约定,一眼能识别保护目标mu: sync.RWMutex{}——零值已足够,显式初始化反而容易误触发拷贝检测func process(m sync.RWMutex) 是危险的,应传指针 *sync.RWMutex
真正难的从来不是选哪个锁,而是想清楚「哪段代码必须原子执行」「哪些访问可以并行」「中间状态是否对外可见」。锁只是工具,逻辑边界划错了,换什么锁都救不了。