文章目录
- 背景
- RWMutex 简介
- 代码验证
- 多个协程请求读锁 `RLock()` 和 `RLock()`
- 读写交错 `RLock()` 和 `Lock()`
- 写入的时候读取
- 读取的时候写入
- 请求多个写`Lock()` 和 `Lock()`
背景
Mutex 互斥锁是严格锁定读和写,如果我们需要单独对读或者写添加锁需要使用 sync包的RWMutex
针对读多写少的情况:
读写锁的原则是
1、可以随便读,多个协程同时读。
2、写的时候,不能读也不能写。
RWMutex 简介
RWMutex 类型一共有 6 个方法,
RLock/RUnlock:RLock 锁定读操作,如果锁已被写操作持有,RLock 方法会被阻塞,直到锁释放;如果锁已被读操作持有,则无限制,可以读取内容。RUnlock 是读操作对应的释放锁的方法。
Lock/Unlock:Lock 锁定读写操作,不管是读操作持有锁,还是写操作持有锁,Lock 方法都会被阻塞,直到锁释放。Unlock 是对应的释放锁方法。一般用于写操作的场景。
rUnlockSlow:检查读操作是否全部释放锁,如果读锁全部释放,才可以唤醒写操作去请求写锁。
RLocker:RLocker 为读操作返回一个 Locker 接口,它的 Lock 方法会调用 RWMutex 类型的 RLock方法,它的 Unlock 方法会调用 RWMutex 类型的 RUnlock方法。
其中 RLock()
和 RLock()
之间并不互斥,可以共享锁,Lock()
和 Lock()
之间还有 RLock()
和 Lock()
之间是互斥的.
代码验证
多个协程请求读锁 RLock()
和 RLock()
package main
import (
"fmt"
"time"
"sync"
)
// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
mu = new(sync.RWMutex)
for i:= 0; i< 1000; i++ {
go readLock(i)
}
time.Sleep(2*time.Second)
}
func readLock(i int) {
mu.RLock()
count++
fmt.Println(i," Read Lock is", count)
mu.RUnlock()
}
如上代码所示, 我们启动1000个协程,每个协程执行的readLock
中都添加了 RLock()
. 执行结果如下:
结果发现,count 数字打印杂乱无章,说明这些协程同时持有锁,多个RLock()
之间并不互斥。
读写交错 RLock()
和 Lock()
写入的时候读取
package main
import (
"fmt"
"time"
"sync"
)
// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
mu = new(sync.RWMutex)
for i := 0; i< 5; i++ {
go readLock(1)
}
for i := 0; i< 5; i++ {
go writLock(1)
}
time.Sleep(30*time.Second)
}
func writLock(i int){
mu.Lock()
fmt.Println(i," Writ Lock start", count)
count++
fmt.Println(i," Writ Lock is", count)
time.Sleep(1 *time.Second)
fmt.Println(i," Writ Lock done", count)
mu.Unlock()
}
func readLock(i int) {
mu.RLock()
fmt.Println(i," Read Lock is", count)
// time.Sleep(10 *time.Second)
fmt.Println(i," Read Lock done")
mu.RUnlock()
}
Lock()
写入的时候,sleep 期间, 使用 RLock()
读取, 结果如下
发现在 write 等待的时候 read 并没有获得锁, 说明 Lock()
锁未释放, RLock()
不能获得锁
读取的时候写入
package main
import (
"fmt"
"time"
"sync"
)
// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
mu = new(sync.RWMutex)
for i := 0; i< 10; i++ {
go readLock(1)
}
for i := 0; i< 10; i++ {
go writLock(1)
}
time.Sleep(15*time.Second)
}
func writLock(i int){
mu.Lock()
fmt.Println(i," Writ Lock start", count)
count++
fmt.Println(i," Writ Lock is", count)
// time.Sleep(1 *time.Second)
fmt.Println(i," Writ Lock done", count)
mu.Unlock()
}
func readLock(i int) {
mu.RLock()
fmt.Println(i," Read Lock is", count)
time.Sleep(10 *time.Second)
fmt.Println(i," Read Lock done")
mu.RUnlock()
}
在 RLock()
sleep 期间, 使用 Lock()
结果如下
read 期间, writ 并没有获得锁。 证明了 RLock()
和 Lock()
是互斥的。
请求多个写Lock()
和 Lock()
package main
import (
"fmt"
"time"
"sync"
)
// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {
mu = new(sync.RWMutex)
for i:= 0; i< 1000; i++ {
go writLock(i)
}
time.Sleep(2*time.Second)
}
func writLock(i int){
mu.Lock()
count++
fmt.Println(i," Writ Lock is", count)
mu.Unlock()
}
启动1000个线程, 使用 Lock()
执行 count ++, 结果如下
发现最红结果是1000,并且是按照顺序进行计算的。 说明多个协程之间的Lock()
是互斥的。