package mainimport ( "fmt" "sync" "time")/*1、定义:go 中的读写锁采取的是写优先的设计,如果已经有一个 writer 在等待请求锁的话,它会阻止新来的请求锁的 reader 获取到锁,所以优先保障 writer。当然,如果有一些 reader 已经请求了锁的话,新请求的 writer 也会等待已经存在的 reader 都释放锁之后才能获取。2、原理:RWMutex 包含一个 Mutex,以及四个辅助字段 writerSem、readerSem、readerCount 和 readerWait:readerCount 是负数:writer持有锁,将后来的reader阻塞休眠readerCount 等于0:reader都已经释放了锁,会唤醒writer,让write持有锁readerCount 不是0:将readerCount 的值保存到readerWait,writer进入阻塞状态3、读写锁易错重入、递归造成死锁写锁等待活跃的reader,活跃的reader等待新来的reader未成对出现4、锁容易出错互斥: 至少一个资源是被排他性独享的,其他线程必须处于等待状态,直到资源被释放。持有和等待:goroutine 持有一个资源,并且还在请求其它 goroutine 持有的资源,也就是咱们常说的“吃着碗里,看着锅里”的意思。不可剥夺:资源只能由持有它的 goroutine 来释放。环路等待:一般来说,存在一组等待进程,P={P1,P2,…,PN},P1 等待 P2 持有的资源,P2 等待 P3 持有的资源,依此类推,最后是 PN 等待 P1 持有的资源,这就形成了一个环路等待的死结。*/func main() { var counter Counter for i := 0; i < 10; i++ { // 10个reader go func() { for { fmt.Println(counter.Count()) // 计数器读操作 time.Sleep(time.Millisecond) } }() } for { // 一个writer counter.Incr() // 计数器写操作 time.Sleep(time.Second) }}// 一个线程安全的计数器type Counter struct { sync.RWMutex count uint64}// 使用写锁保护func (c *Counter) Incr() { c.Lock() c.count++ c.Unlock()}// 使用读锁保护func (c *Counter) Count() uint64 { c.RLock() defer c.RUnlock() return c.count}