sync.Mutex 与 sync.RWMutex
加锁与读写锁模式
sync.Mutex 与 sync.RWMutex 是 CoddyKit 上的免费 Go Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。
为什么需要互斥锁
当多个协程共享可变状态时,并发读写会导致数据竞争。互斥锁会将访问串行化,使同一时刻只有一个协程进入临界区。
sync.Mutex 基础
在读取或写入共享状态前调用 Lock;完成后调用 Unlock。使用 defer 可确保即使函数发生 panic,也一定会解锁。
var mu sync.Mutex
var counter int
func inc() {
mu.Lock()
defer mu.Unlock()
counter++
}在结构体中嵌入 Mutex
将互斥锁嵌入它所保护的结构体中。按照惯例,互斥锁应声明在它所保护的字段正上方。
type SafeCounter struct {
mu sync.Mutex
v map[string]int
}
func (c *SafeCounter) Inc(key string) {
c.mu.Lock()
defer c.mu.Unlock()
c.v[key]++
}不要复制 Mutex
Mutex 在首次使用后绝不能复制。请通过指针传递它,或将它嵌入通过指针传递的结构体中。go vet 工具可以检测复制操作。
sync.RWMutex
sync.RWMutex 允许多个读取方并发读取,但同一时刻只允许一个写入方。读取占主导且写入很少时,可以使用它来提高吞吐量。
var rw sync.RWMutex
var data map[string]int
func read(k string) int {
rw.RLock()
defer rw.RUnlock()
return data[k]
}
func write(k string, v int) {
rw.Lock()
defer rw.Unlock()
data[k] = v
}RLock 与 Lock
RLock 获取读锁(共享);Lock 获取写锁(排他)。等待中的写锁会阻止新的读锁,从而避免写入方饥饿。
TryLock(Go 1.18 及更高版本)
mu.TryLock() 仅在锁当前未被占用时获取锁,并返回一个布尔值。在不允许阻塞的场景中,这非常有用。
if mu.TryLock() {
defer mu.Unlock()
// critical section
}死锁
当协程 A 持有锁 1 并等待锁 2,而协程 B 持有锁 2 并等待锁 1 时,就会发生死锁。始终按照相同顺序获取锁,并让临界区保持简短。
锁粒度
粗粒度锁更容易理解,但会降低并发性。细粒度加锁可以提高吞吐量,但会增加复杂性和死锁风险。请从粗粒度锁开始,只有在性能分析显示存在竞争时再进行优化。
互斥锁与通道
当需要保护由许多读取方和写入方共享的状态时,请使用互斥锁。当需要在协程之间转移数据所有权时,请使用通道。通道用于通信,互斥锁用于同步。
sync.Locker 接口
sync.Locker 是一个包含 Lock 和 Unlock 的接口。Mutex 和 RWMutex 都实现了该接口,因此辅助函数可以接受任意一种类型。
快速检查
什么时候应该使用 sync.RWMutex 而不是 sync.Mutex?
回顾:Mutex 与 RWMutex
要点:
- Mutex 会串行化访问;始终使用 defer 调用 Unlock
- 首次使用后绝不要复制 Mutex
- RWMutex:多个读取者 OR 一个写入者
- 以一致的顺序获取锁,避免死锁
常见问题解答
「sync.Mutex 与 sync.RWMutex」课时是免费的吗?
是的 — 「sync.Mutex 与 sync.RWMutex」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。
「sync.Mutex 与 sync.RWMutex」这节课中我会学到什么?
加锁与读写锁模式 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Go Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「sync.Mutex 与 sync.RWMutex」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Go Academy 课中编写并运行代码吗?
能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- sync.Mutex 与 sync.RWMutex
- sync.WaitGroup
- sync.Once 与 sync.Map
- 竞态检测器与安全模式