在Go中,sync.RWMutex(读写互斥锁)允许多个读操作同时进行,但写操作是互斥的。它的关键方法是:
RLock():获取读锁,可以并发多个 goroutine 同时获取,只要没有写锁持有。Lock():获取写锁,不能与任何读锁或写锁同时持有,保证独占访问。
关系总结:
- 多个
RLock()可以同时存在,只要没有Lock()(写锁)持有。 - 一旦有任何
Lock()持有(写锁),所有的RLock()和Lock()都必须等待。 - 一旦有任何
RLock()存在,不能执行Lock(),因为写锁需要独占。
简单示意:
| 状态 | 允许的操作 |
|---|---|
多个RLock()持有同时存在 | 可以同时进行,相互不阻塞(读并发) |
有Lock()(写锁)持有 | 其他RLock()和Lock()都被阻塞 |
无Lock(),有RLock() | 其他RLock()也可以继续,写锁等待直到所有RLock()释放 |
有RLock()时调用Lock() | 阻塞,等待所有RLock()释放,才能获得写锁 |
简单理解:
RLock()与RLock()可以同时持有Lock()会等待直到所有RLock()都释放- 出现
Lock(),其他RLock()和Lock()都会暂停
sync.RWMutex(读写互斥锁) RLock 和 lock 有优先级的区别么?
在 sync.RWMutex 中,RLock()(读锁)和 Lock()(写锁)没有优先级的区别,它们的行为如下:
Lock()(写锁) :用于独占锁,获得写锁的 goroutine 会阻塞,直到没有其他读锁或写锁持有时才会获得锁。RLock()(读锁) :允许多个读操作同时持有,只要没有任何写锁在持有中。如果有任何写锁正在使用,RLock()会阻塞。
核心点:
- 没有优先级排序:
sync.RWMutex不会偏向读锁或写锁。 - 可能发生“写饥饿” :如果持续有很多读锁(
RLock())在获取,写锁(Lock())可能长时间阻塞。或者反之,如果持续有写锁,新的读锁会被阻塞。
小结:
RLock()和Lock()不存在优先级关系,也不会自动偏向某一方。- 这意味着,读操作可以连续进行,除非有写锁等待或已持有。而写操作会等待直到没有任何读锁或写锁。
如果需要避免某一方饥饿,通常需要自己设计一些调度逻辑,或者使用其他同步机制。