
RWMutex读写锁
Demo示例
合理使用 RWMutex:
- 写操作(initServices)使用 Lock()/Unlock()。
- 读操作(getServices)使用 RLock()/RUnlock()。
- 允许多个 goroutine 并发读,提高性能。
go
package main
import (
"fmt"
"sync"
"time"
)
// 模拟服务依赖结构
type ServiceDeps struct {
AppName string
Version string
}
var (
depsMu sync.RWMutex
deps *ServiceDeps // 全局共享数据,只写一次,多次读
)
// 安全读取 deps
func getServices() *ServiceDeps {
depsMu.RLock()
defer depsMu.RUnlock()
return deps
}
// 初始化 deps(模拟“单线程写”)
func initServices() {
depsMu.Lock()
defer depsMu.Unlock()
// Mock 数据
deps = &ServiceDeps{
AppName: "PriceMonitor",
Version: "v1.0.0",
}
fmt.Println("✅ Services initialized!")
}
func main() {
// 模拟应用启动:单线程初始化
initServices()
// 模拟多个并发请求(goroutine)同时读取
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
time.Sleep(time.Millisecond * 10) // 模拟处理延迟
s := getServices()
if s != nil {
fmt.Printf("Worker %d: App=%s, Version=%s\n", id, s.AppName, s.Version)
} else {
fmt.Printf("Worker % d: ❌ services not ready!\n", id)
}
}(i)
}
wg.Wait()
fmt.Println("🎉 All workers done.")
}结果
text
✅ Services initialized!
Worker 0: App=PriceMonitor, Version=v1.0.0
Worker 3: App=PriceMonitor, Version=v1.0.0
Worker 1: App=PriceMonitor, Version=v1.0.0
Worker 4: App=PriceMonitor, Version=v1.0.0
Worker 2: App=PriceMonitor, Version=v1.0.0
🎉 All workers done.疑问
如果不加读锁会怎么样?
我之前以为,如果是读的话则可以多个请求读?写的话则会加锁,只有一个请求操作。那么感觉读锁没啥用,是否可以不显式的加读锁呢?好像貌似也没啥问题。
但其实上,加读锁是为了防止有写的情况。
- 多个 goroutine 可以同时读(调用
RLock())✅ - 写操作是独占的:只要有一个 goroutine 在写(
Lock()),其他读和写都必须等待 ✅ - 读和写不能同时进行:有读时不能写,有写时不能读 ✅
这正是“读写锁”(Read-Write Mutex)的核心语义。
注意,读锁和写锁是互斥的,所以多并发读的时候还是需要加上`RLock()/RUnlock()`的,避免并发修改
什么情况下可以不加锁?
- 只有当满足以下所有条件时,才可以无锁读:
- 变量在程序启动时一次性初始化(比如 init() 函数中)
- 之后永远不再修改
- 且初始化发生在 main 执行之前(或在 main 中单线程完成)

