多个gotoutine同时操作一个资源,这个资源叫做临界区
在并发条件下,如果多个goroutine在没有相互同步的情况下,访问某个共享的资源,会处于相互竞争的状态,导致并发中的资源/数据竞争问题。如下面的程序,2个goroutine 对count各执行10w 次加一操作,打印出的最终结果很有可能不是20w

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var (
  7. wg sync.WaitGroup
  8. count int
  9. )
  10. func incCount() {
  11. defer wg.Done()
  12. for i := 0; i < 100000; i++ {
  13. count ++
  14. }
  15. }
  16. func main() {
  17. wg.Add(2)
  18. go incCount()
  19. go incCount()
  20. wg.Wait()
  21. fmt.Println(count)
  22. }

执行 go run —race main.go 会告诉你有数据竞争DATA RACE的问题

  1. go run -race main.go
  2. ==================
  3. WARNING: DATA RACE
  4. Read at 0x0000005ef648 by goroutine 7:
  5. ==================
  6. 181708
  7. Found 1 data race(s)
  8. exit status 66

互斥锁同时有且只有一个线程进入临界区,其他的线程则在等待锁,当互斥锁释放后,等待锁的线程才可以获取锁进入临界区,当多个线程同时等待同一个锁,唤醒的策略是随机的
Mutex是互斥锁

  1. // Lock 用于锁住 m,如果 m 已经被加锁,则 Lock 将被阻塞,直到 m 被解锁。
  2. func (m *Mutex) Lock()
  3. // Unlock 用于解锁 m,如果 m 未加锁,则该操作会引发 panic
  4. func (m *Mutex) Unlock()

eg:

  1. package main
  2. import (
  3. "fmt"
  4. "sync"
  5. )
  6. var (
  7. wg sync.WaitGroup
  8. count int32
  9. mu sync.Mutex
  10. )
  11. func incCount() {
  12. defer wg.Done()
  13. for i := 0; i < 100000; i++ {
  14. mu.Lock()
  15. count++
  16. mu.Unlock()
  17. }
  18. }
  19. func main() {
  20. wg.Add(2)
  21. go incCount()
  22. go incCount()
  23. wg.Wait()
  24. fmt.Println(count)
  25. }

参考

https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-sync-primitives/
http://xiaorui.cc/archives/5951
https://cloud.tencent.com/developer/article/1596863