各种锁
·
更新于 ·
giftia
Go 锁
互斥锁 sync.Mutex
type Mutex struct {
state int32 // 锁状态:0 未加锁,1 已加锁
sema uint32 // 信号量,用于等待队列
}
读写锁 sync.RWMutex
读读共享,读写互斥,写写互斥。
type RWMutex struct {
w Mutex
writerSem uint32
readerSem uint32
readerCount atomic.Int32 // 当前持有读锁的读操作数
readerWait atomic.Int32 // 等待释放的读操作数
}
使用注意
- 同一个协程不能连续多次调用 Lock,否则死锁
- 锁范围尽量小,避免其他协程长时间等待
- mutex 传递时须传指针,否则是实例拷贝,锁会失效
- 善用 defer 确保解锁
- 使用
-race检测数据竞争:go test -race/go build -race - 能用 channel 的场景别用 lock
MySQL 锁
表锁与行锁
-- 表锁
LOCK TABLES table_name [READ|WRITE];
UNLOCK TABLES;
-- 行锁
SELECT ... FOR UPDATE; -- 排他锁
SELECT ... LOCK IN SHARE MODE; -- 共享锁
共享锁与排他锁
共享锁(读锁):多个事务可同时持有。排他锁(写锁):同一时间只允许一个事务持有。
间隙锁
锁定索引记录之间的间隙,防止幻读。
Redis 锁
分布式锁
# 推荐:原子操作
SET key value NX EX timeout
优化点
- 设置过期时间,防止死锁
- 看门狗定期检查主线程,给锁续期
- 加 UUID,防止锁被误释放
其他锁
乐观锁 & 悲观锁
- 乐观锁:假设冲突少,更新时检测(如版本号)
- 悲观锁:假设冲突一定发生,先加锁再操作
自旋锁
加锁失败时不阻塞,循环尝试直到成功。适用于锁持有时间短的场景。