一、前言
go语言类似Java JUC包也提供了一些列用于多线程之间进行同步的措施,比如低级的同步措施有 锁、CAS、原子变量操作类。本节我们先来看看go中读写锁,读写锁相比互斥锁来说并发度更高,在读多写少情况下比较实用。
二、读写锁
在go中可以使用sync.RWMutex获取一个读写锁,读写锁是读写互斥锁,读锁可以被任意多的读goroutine持有,但是写锁只能被某一个goroutine持有。当一个goroutine获取读锁后,其他goroutine也可以获取到读锁,但是如果这时候有goroutine尝试获取写锁,则获取写锁的线程将会被阻塞,这时候如果再有goroutine尝试获取读锁,则其也会被阻塞。
当某个goroutine获取到写锁后,其后尝试获取读锁的goroutine都会被阻塞。
另外读锁是可重入锁,也就是同一个goroutine在可以在持有读锁的情况下再次获取读锁。
在go中获取读锁和写锁方式如下:
var rwLock sync.RWMutex
rwLock.RLock()//获取读锁
rwLock.RUnlock()//释放读锁
rwLock.Lock()//获取写锁
rwLock.Unlock()//释放写锁
三、读写锁例子
3.1 验证多个goroutine可以同时获取读锁
首先我们来验证下多个goroutine可以同时获取读锁:
package main
import (
"fmt"
"sync"
)
var (
wg sync.WaitGroup //信号量
)
var rwlock sync.RWMutex //读写锁
func main() {
wg.Add(1)
//1.
rwlock.RLock()
fmt.Println("--main goroutine get rlock---")
//2.
go func() {
rwlock.RLock()//2.1
fmt.Println("--new goroutine get rlock---")
rwlock.RUnlock()//2.2
wg.Done()//2.3
}()
wg.Wait()//2.4
rwlock.RUnlock()//2.5
}
如上代码首先创建了一个读写锁rwlock,和一个同步用的wg对象
main函数所在goroutine内代码(1)获取到了读锁,然后开启了一个新的goroutine,新goroutine内首先获取读锁,然后在释放,最后让信号量减去1.
main函数所在goroutine在代码2.4等待新goroutine运行结束然后在释放读锁
这里假设同时只有一个goroutine可以获取读锁,则由于main所在goroutine已经在代码1获取到了读锁