Golang中Mutex锁锁定对象解析及缓存锁区分与实现疑问
在Go语言中,Mutex锁到底锁定的是什么?
Go 中的sync.Mutex并不直接锁定任何对象或内存区域,它的核心作用是保证临界区代码的互斥执行——同一时间只能有一个 goroutine 进入被它包裹的代码块。
你可以把它理解成一个"准入令牌":拿到令牌的 goroutine 才能操作共享资源,没拿到的必须等待。它通过控制代码执行的排他性,间接避免共享数据被并发读写破坏。
针对代码区分globalLock与EntryLock,以及实现单key锁定
先看给出的结构体定义:
type cacheImpl struct { globalLock sync.Mutex EntryLock map[string]*sync.Mutex abc map[string]int }
二者的区别与锁定对象
- globalLock:全局互斥锁,负责保护
abc这个 map 的结构安全。比如对 map 执行添加/删除 key、初始化这类修改结构的操作,或者遍历整个 map 时,必须用它来保证并发安全。它锁定的是整个 map 结构,只要它被持有,所有涉及 map 结构变更的操作都得等待。 - EntryLock:以 string 为 key 的锁集合,作用是为
abc中单个 key 对应的 int 值提供细粒度锁定。不同 key 的操作可以并发执行,不用互相阻塞,比全局锁的性能更优。
如何创建EntryLock实现单key锁定
要实现每个 key 对应独立的锁,需要在首次操作该 key 时创建对应的 Mutex,且创建锁的过程要保证并发安全,通常结合 globalLock 来实现:
完整示例代码
1. 初始化 cache
func NewCache() *cacheImpl { return &cacheImpl{ abc: make(map[string]int), EntryLock: make(map[string]*sync.Mutex), } }
2. 单key操作的示例方法
func (c *cacheImpl) GetOrSet(key string, val int) int { // 先获取全局锁,检查并创建对应key的锁,减少全局锁持有时间 c.globalLock.Lock() lock, ok := c.EntryLock[key] if !ok { lock = &sync.Mutex{} c.EntryLock[key] = lock } c.globalLock.Unlock() // 持有单个key的锁,操作对应的value lock.Lock() defer lock.Unlock() if v, exists := c.abc[key]; exists { return v } c.abc[key] = val return val }
3. 删除key时清理锁(避免内存泄漏)
func (c *cacheImpl) Delete(key string) { // 先从锁集合中移除对应key的锁 c.globalLock.Lock() lock, ok := c.EntryLock[key] if ok { delete(c.EntryLock, key) } c.globalLock.Unlock() // 锁定对应key的锁,确保没有并发操作 if lock != nil { lock.Lock() defer lock.Unlock() } // 最后删除map中的key c.globalLock.Lock() delete(c.abc, key) c.globalLock.Unlock() }
内容的提问来源于stack exchange,提问作者SWATHI.M SHETTY
相关产品推荐
相关产品推荐

