package main
import (
"fmt"
"sync"
)
type MemoryLock struct {
mu sync.Mutex
locks map[string]*sync.Mutex
}
func NewMemoryLock() *MemoryLock {
return &MemoryLock{
locks: make(map[string]*sync.Mutex),
}
}
func (l *MemoryLock) Lock(key string) {
l.mu.Lock()
lock, ok := l.locks[key]
if !ok {
lock = &sync.Mutex{}
l.locks[key] = lock
}
l.mu.Unlock()
lock.Lock()
}
func (l *MemoryLock) Unlock(key string) {
l.mu.Lock()
defer l.mu.Unlock()
lock, ok := l.locks[key]
if ok {
lock.Unlock()
delete(l.locks, key)
}
}
func main() {
lock := NewMemoryLock()
keys := []string{"key1", "key2", "key3"}
var wg sync.WaitGroup
wg.Add(len(keys))
for _, key := range keys {
go func(k string) {
lock.Lock(k)
defer lock.Unlock(k)
// 执行需要加锁保护的操作
fmt.Printf("操作 %s\n", k)
}(key)
}
wg.Wait()
}
这个示例代码中,我们定义了一个 MemoryLock
结构体,其中包含一个互斥锁 mu
和一个映射表 locks
。locks
用于保存每个 key
对应的互斥锁。
在 Lock
方法中,首先通过互斥锁 mu
对 locks
进行加锁保护。然后检查 locks
中是否已经存在该 key
对应的锁。如果不存在,则创建一个新的互斥锁,并将其存储到 locks
中。最后释放 mu
锁,并对获取到的互斥锁进行加锁操作。
在 Unlock
方法中,首先通过互斥锁 mu
对 locks
进行加锁保护。然后检查 locks
中是否存在该 key
对应的锁。如果存在,则对该锁进行解锁操作,并从 locks
中删除该 key
。最后释放 mu
锁。
在 main
函数中,我们创建了一个 MemoryLock
实例 lock
。然后使用 WaitGroup
来等待所有协程执行完毕。
接下来,我们遍历 keys
切片,并针对每个 key
启动一个协程。在协程中,首先调用 lock.Lock()
方法对指定的 key
进行加锁操作。然后执行需要加锁保护的操作,这里只是简单地打印一条信息。最后调用 lock.Unlock()
方法对指定的 key
进行解锁操作。
通过这种方式,我们可以实现基于内存的按照 key
加锁和解锁的功能。每个 key
对应一个独立的互斥锁,在并发场景下可以有效地控制对不同 key
的并发访问。