建设厅八大员报名网站公关公司经营范围
文章目录
- 背景
 - 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 mainimport ("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 mainimport ("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 mainimport ("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 mainimport ("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() 是互斥的。
