一.互斥锁
- Go语言中多个协程操作一个变量时会出现冲突的问题
- go run -race 可以查看竞争
- 可以使用
sync.Mutex对内容加锁 - 互斥锁的使用场景
- 多个goroutine访问同一个函数(代码段)
- 这个函数操作一个全局变量
- 为了保证共享变量安全性,值合法性
- 使用互斥锁模拟售票窗口 ```go package main
import ( “fmt” “sync” “time” “math/rand” )
var ( //票数 num = 100 wg sync.WaitGroup //互斥锁 mu sync.Mutex )
func sellTicker(i int) { defer wg.Done() for { //加锁,多个goroutine互斥 mu.Lock() if num >= 1 { fmt.Println(“第”, i, “个窗口卖了”, num) num = num - 1 } //解锁 mu.Unlock()
if num <= 0 {break}//添加休眠,防止结果可能出现在一个goroutine中time.Sleep(time.Duration(rand.Int63n(1000) * 1e6))
}
}
func main() { //设置随机数种子 rand.Seed(time.Now().UnixNano()) //计算器的起始值和票数相同 wg.Add(4) go sellTicker(1) go sellTicker(2) go sellTicker(3) go sellTicker(4) wg.Wait()
fmt.Println(“所有票卖完”) }
<a name="04cd007c"></a># 二.RWMutex读写锁- RWMutex 源码如下```go// There is a modified copy of this file in runtime/rwmutex.go.// If you make any changes here, see if you should make them there.// A RWMutex is a reader/writer mutual exclusion lock.// The lock can be held by an arbitrary number of readers or a single writer.// The zero value for a RWMutex is an unlocked mutex.//// A RWMutex must not be copied after first use.//// If a goroutine holds a RWMutex for reading and another goroutine might// call Lock, no goroutine should expect to be able to acquire a read lock// until the initial read lock is released. In particular, this prohibits// recursive read locking. This is to ensure that the lock eventually becomes// available; a blocked Lock call excludes new readers from acquiring the// lock.type RWMutex struct {w Mutex // held if there are pending writerswriterSem uint32 // semaphore for writers to wait for completing readersreaderSem uint32 // semaphore for readers to wait for completing writersreaderCount int32 // number of pending readersreaderWait int32 // number of departing readers}
Go语言标准库中API如下
type RWMutexfunc (rw *RWMutex) Lock()//禁止其他协程读写func (rw *RWMutex) Unlock()func (rw *RWMutex) RLock()//禁止其他协程写入,只能读取func (rw *RWMutex) RUnlock()func (rw *RWMutex) RLocker() Locker
Go语言中的map不是线程安全的,多个goroutine同时操作会出现错误.
- RWMutex可以添加多个读锁或一个写锁.读写锁不能同时存在.
- map在并发下读写就需要结合读写锁完成
- 互斥锁表示锁的代码同一时间只能有一个人goroutine运行,而读写锁表示在锁范围内数据的读写操作 ```go package main
import ( “fmt” “sync” “strconv” )
func main() { var rwm sync.RWMutex m := make(map[string]string) var wg sync.WaitGroup wg.Add(10) for i := 0; i < 10; i++ { go func(j int) { //没有锁在map时可能出现问题 rwm.Lock() m[“key”+strconv.Itoa(j)] = “value” + strconv.Itoa(j) fmt.Println(m) rwm.Unlock() wg.Done() }(i) } wg.Wait() fmt.Println(“程序结束”) } ```
