一.互斥锁

  • 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()

  1. if num <= 0 {
  2. break
  3. }
  4. //添加休眠,防止结果可能出现在一个goroutine中
  5. 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(“所有票卖完”) }

  1. <a name="04cd007c"></a>
  2. # 二.RWMutex读写锁
  3. - RWMutex 源码如下
  4. ```go
  5. // There is a modified copy of this file in runtime/rwmutex.go.
  6. // If you make any changes here, see if you should make them there.
  7. // A RWMutex is a reader/writer mutual exclusion lock.
  8. // The lock can be held by an arbitrary number of readers or a single writer.
  9. // The zero value for a RWMutex is an unlocked mutex.
  10. //
  11. // A RWMutex must not be copied after first use.
  12. //
  13. // If a goroutine holds a RWMutex for reading and another goroutine might
  14. // call Lock, no goroutine should expect to be able to acquire a read lock
  15. // until the initial read lock is released. In particular, this prohibits
  16. // recursive read locking. This is to ensure that the lock eventually becomes
  17. // available; a blocked Lock call excludes new readers from acquiring the
  18. // lock.
  19. type RWMutex struct {
  20. w Mutex // held if there are pending writers
  21. writerSem uint32 // semaphore for writers to wait for completing readers
  22. readerSem uint32 // semaphore for readers to wait for completing writers
  23. readerCount int32 // number of pending readers
  24. readerWait int32 // number of departing readers
  25. }
  • Go语言标准库中API如下

    1. type RWMutex
    2. func (rw *RWMutex) Lock()//禁止其他协程读写
    3. func (rw *RWMutex) Unlock()
    4. func (rw *RWMutex) RLock()//禁止其他协程写入,只能读取
    5. func (rw *RWMutex) RUnlock()
    6. 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(“程序结束”) } ```