giftiaのblog

各种锁

· 更新于 · 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,防止锁被误释放

其他锁

乐观锁 & 悲观锁

  • 乐观锁:假设冲突少,更新时检测(如版本号)
  • 悲观锁:假设冲突一定发生,先加锁再操作

自旋锁

加锁失败时不阻塞,循环尝试直到成功。适用于锁持有时间短的场景。