一、介绍
sync.RWMutex 为读写锁,lock为写锁定 ,Unlock 为写解锁,RLock为读锁,RUnlock为读解锁。
二、场景
适用于场景:多读一写,读可以同时进行,但是写只能一个写,读写是互斥的要么只能读或者只能写
三、代码测试
功能性测试
第一种场景 测试内容 : 读锁存在的情况下,同时出现读和写的操作,此时优先获取写锁
package main
import (
"testing"
"fmt"
"sync"
"time"
)
var rwlock = &sync.RWMutex{}
var wg = &sync.WaitGroup{}
func TestRWMutex(t *testing.T) {
//读
wg.Add(1)
go rlockwork()
time.Sleep(2 * time.Second)
//读
wg.Add(1)
go rlock()
//写
wg.Add(1)
go wlock()
wg.Wait()
}
func wlock() {
rwlock.Lock()
fmt.Println("加写锁")
fmt.Println("写任务执行")
defer func() {
rwlock.Unlock()
fmt.Println("最后写解锁完毕")
wg.Done()
}()
fmt.Println("准备解开写锁")
}
func rlock() {
rwlock.RLock()
fmt.Println("加读锁")
fmt.Println("读任务执行")
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
func rlockwork() {
rwlock.RLock()
fmt.Println("加读锁====首先获取读锁")
fmt.Println("读任务执行")
time.Sleep(4 * time.Second)
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
输出结果:
=== RUN TestRWMutex
加读锁====首先获取读锁
读任务执行
准备解开读锁
最后读解锁完毕
加写锁
写任务执行
准备解开写锁
最后写解锁完毕
加读锁
读任务执行
准备解开读锁
最后读解锁完毕
--- PASS: TestRWMutex (4.00s)
PASS
Process finished with exit code 0
第二种场景 功能性测试
测试内容: 同时开启2个线程去争夺读锁和写锁,此时都有机会被获取
package main
import (
"testing"
"fmt"
"sync"
"time"
)
var rwlock = &sync.RWMutex{}
var wg = &sync.WaitGroup{}
func TestRWMutex(t *testing.T) {
//读
//wg.Add(1)
//go rlockwork()
time.Sleep(2 * time.Second)
//读
wg.Add(1)
go rlock()
//写
wg.Add(1)
go wlock()
wg.Wait()
}
func wlock() {
rwlock.Lock()
fmt.Println("加写锁")
fmt.Println("写任务执行")
defer func() {
rwlock.Unlock()
fmt.Println("最后写解锁完毕")
wg.Done()
}()
fmt.Println("准备解开写锁")
}
func rlock() {
rwlock.RLock()
fmt.Println("加读锁")
fmt.Println("读任务执行")
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
func rlockwork() {
rwlock.RLock()
fmt.Println("加读锁====首先获取读锁")
fmt.Println("读任务执行")
time.Sleep(4 * time.Second)
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
输出结果:
=== RUN TestRWMutex
加写锁
写任务执行
准备解开写锁
最后写解锁完毕
加读锁
读任务执行
准备解开读锁
最后读解锁完毕
--- PASS: TestRWMutex (2.00s)
PASS
Process finished with exit code 0
分割线======================================分割线
=== RUN TestRWMutex
加读锁
读任务执行
准备解开读锁
最后读解锁完毕
加写锁
写任务执行
准备解开写锁
最后写解锁完毕
--- PASS: TestRWMutex (2.00s)
PASS
Process finished with exit code 0
第三种场景 功能性测试
测试内容:写锁存在的情况,同时开启2个线程去争夺读锁和写锁,优先获取读锁
package main
import (
"testing"
"fmt"
"sync"
"time"
"runtime"
)
var rwlock = &sync.RWMutex{}
var wg = &sync.WaitGroup{}
func TestRWMutex(t *testing.T) {
//写
runtime.GOMAXPROCS(runtime.NumCPU())
wg.Add(1)
go wlock()
time.Sleep(2 * time.Second)
//读
wg.Add(1)
go rlock()
//写
wg.Add(1)
go wlock()
wg.Wait()
}
func wlock() {
rwlock.Lock()
fmt.Println("加写锁")
fmt.Println("写任务执行")
time.Sleep(4 * time.Second)
defer func() {
rwlock.Unlock()
fmt.Println("最后写解锁完毕")
wg.Done()
}()
fmt.Println("准备解开写锁")
}
func rlock() {
rwlock.RLock()
fmt.Println("加读锁")
fmt.Println("读任务执行")
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
func rlockwork() {
rwlock.RLock()
fmt.Println("加读锁====首先获取读锁")
fmt.Println("读任务执行")
//time.Sleep(4 * time.Second)
defer func() {
rwlock.RUnlock()
fmt.Println("最后读解锁完毕")
wg.Done()
}()
fmt.Println("准备解开读锁")
}
输出结果:
=== RUN TestRWMutex
加写锁
写任务执行
准备解开写锁
最后写解锁完毕
加读锁
读任务执行
准备解开读锁
最后读解锁完毕
加写锁
写任务执行
准备解开写锁
最后写解锁完毕
--- PASS: TestRWMutex (8.01s)
PASS
Process finished with exit code 0
总结:
1.读锁存在的情况下,同时出现读和写的操作,此时优先获取写锁
2.同时开启2个线程去争夺读锁和写锁,此时都有机会被获取
3.写锁存在的情况,同时开启2个线程去争夺读锁和写锁,优先获取读锁
注:(golang版本go version go1.11.4 darwin/amd64)
有疑问加站长微信联系(非本文作者)