你知道互斥锁和读写锁的指针类型都实现了哪一个接口吗?

它们都实现了 sync.Locker 接口。


sync.Locker 接口的定义

sync 包中,Locker 是一个极简的接口,只有两个方法:

type Locker interface {
    Lock()
    Unlock()
}

谁实现了它?

  • *sync.MutexLock()Unlock() 方法,所以 *Mutex 实现了 sync.Locker
  • *sync.RWMutex 虽然有四个方法(LockUnlockRLockRUnlock),但它也包含 Lock()Unlock(),因此它的指针类型同样实现了 sync.Locker

注意,一定是 指针类型*Mutex*RWMutex)实现了该接口,值类型不行,因为 LockUnlock 的接收者是带指针的(需要修改锁的内部状态,且锁值不可被复制)。


这个接口有什么用?

当你的函数或结构体只关心“获取排他锁 / 释放排他锁”这个行为,而不在乎底层是互斥锁还是读写锁的写锁时,就可以用 sync.Locker 做抽象。

例子:条件变量 sync.Cond

条件变量需要一把锁,它的构造函数参数就是 sync.Locker

var mu sync.Mutex
cond := sync.NewCond(&mu) // *Mutex 作为 Locker 传入

也可以传入 *RWMutex(它会把写锁传给 Cond,因为 Cond 调的是 Lock/Unlock):

var rw sync.RWMutex
cond := sync.NewCond(&rw) // *RWMutex 作为 Locker,此时上的是写锁

例子:编写工具函数

如果你写一个需要锁的通用辅助函数:

func doSomethingWithLock(l sync.Locker) {
    l.Lock()
    defer l.Unlock()
    // ... 临界区
}

调用时,*sync.Mutex*sync.RWMutex 都能直接传入,灵活性很高。


为什么它们是指针类型才实现?

因为 Lock / Unlock 的方法接收者是指针:

func (m *Mutex) Lock()
func (m *Mutex) Unlock()

值接收者的方法集包含值方法和指针方法,但指针接收者的方法集只属于指针类型。所以:

  • var m sync.Mutex —— m 的值类型没有 Lock/Unlock 方法(因为编译器不会自动解引用取地址来满足接口)。
  • var m *sync.Mutex —— m 是指针,可以实现 sync.Locker

这条规则也避免了无意中复制锁导致的死锁或锁失效问题,强化了“锁不能复制”的约束。


总结

答案是:sync.Locker

  • *sync.Mutex*sync.RWMutex 都实现了它。
  • 这个接口抽象出了“排他加锁/解锁”的基本能力,常用于条件变量或其他只需要锁行为的通用代码中。
posted @ 2026-05-13 14:27  Acyclonepl  阅读(5)  评论(0)    收藏  举报