跳到主要内容

go-互斥锁与读写锁

  • Go 里的互斥锁和读写锁,本质上都是为了解决:多个 goroutine 并发访问共享数据时,避免数据竞争(data race)。
  • 互斥锁Mutex:同一时间只允许一个 goroutine 进入。
  • 读写锁RWMutex:允许多个 goroutine 同时读,但写的时候必须独占。
  • Go 主要通过 sync 包使用锁。

为什么需要锁​

  • 如果多个 goroutine 同时修改一个变量,会产生数据竞争问题,导致数据不准确
  • 保护多个 goroutine 共享的数据,防止它们同时修改或读写数据,产生数据竞争

互斥锁​

  • Go 里的互斥锁 Mutex解决的是**:**多个 goroutine 同时访问、修改同一份共享数据时,避免发生数据竞争
  • 通过标准库的sync.Mutex来实现互斥锁
  • 用来保护多个 goroutine 共同访问的共享资源
    • 通过互斥锁来保护资源
    • 使同一时间只有一个goroutine能访问

互斥理解​

  • 互:多个 goroutine 之间
  • 斥:互相排斥,不能同时进入

读写锁​

  • 读写锁 RWMutex:读可以多人同时读;写还是独占
  • RLock():读锁
    • 只想读数据,不修改数据

defer Unlock​

  • defer:把一个函数调用延迟到当前函数结束前执行
  • defer Unlock:保证当前函数结束时自动释放锁。
go
mu.Lock()
defer mu.Unlock()

count++

使用场景​

多个goroutine协程改同一个内存数据问题,避免出现数据竞争,加上锁

缓存​

  • 缓存的特点:读的次数比较多,写比较少
  • 有人要改缓存,需要加锁, 其他人需要等待,等他改完再继续

配置读取​

  • 支付配置
  • 系统配置
  • 在修改配置时,就先锁住,等修改完成后再继续读

计数器​

  • 统计请求次数
    • 比如多个请求同时进来,这些请求都同时修改数据,不加锁的话,导致最终的统计的次数不正确
    • 多个请求进来,那就排队,一个改完,下一个再改
go
var mu sync.Mutex

func add() {
mu.Lock()
defer mu.Unlock()

count++
}

map 的并发安全​

  • go的map不是并发安全的
  • 如果2个不同的goroutine同时读和写,多个线程同时操作一个map。go会直接pannic报错,导致竟态条件,产生数据竞争
  • 属于并发读写,不安全