Mutex 与 RWMutex
Mutex 互斥锁的核心规则与写法是什么?
sync.Mutex: 一次只允许一个 goroutine 进入临界区;- 使用场景: 保护共享变量, map, 计数器等可变数据;
- 解锁要求:
Lock成功后必须调用Unlock;
package main
import "sync"
func main() {
var mu sync.Mutex
count := 0
mu.Lock() // 加锁,进入临界区
count++ // 访问共享数据
mu.Unlock() // 解锁,离开临界区
println(count)
}
- 临界区: 必须作为整体保护的共享数据操作区间;所有访问同一份可变数据的路径应遵守同一锁约定;
- 使用限制: Mutex 零值可用,开始使用后不得复制;锁不是可重入锁,同一执行路径重复 Lock 而不解锁会阻塞;
RWMutex 读写锁的核心规则与写法是什么?
sync.RWMutex: 适合读多写少场景的读写锁;- 读锁: 多个 goroutine 可同时持有
RLock, 阻塞写; - 写锁:
Lock独占访问并阻塞其他读写; - defer 解锁: 加锁成功后可用
defer保证释放;
// 读1 ─┐
// 读2 ─┼── 可以同时读取
// 读3 ─┘
// 写入 ─── 等所有读锁释放 ─── 修改配置
var (
mu sync.RWMutex
config map[string]string
)
func Get(key string) string {
mu.RLock() // 多个 goroutine 可同时读取配置
defer mu.RUnlock() // 读取结束后释放读锁
return config[key]
}
func Reload(newConfig map[string]string) {
mu.Lock() // 独占访问,等待已有读锁释放
defer mu.Unlock() // 更新结束后释放写锁
config = newConfig
}
- 选择边界: 读多写少只是候选条件,锁开销与竞争程度仍需测量;RWMutex 不支持从读锁升级为写锁,也不支持降级;
- 共享数据边界: 示例 Reload 直接保存 map,调用方发布后不得绕过这把锁继续修改该 map;
- API 依据: sync;