本章介绍go语言内置的加锁机制。
- Mutex - 互斥锁
- RWMutex - 读写互斥锁
1.Mutex
Mutex是一个互斥锁,可以作为为其他结构体的字段,零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。
基本用法:
// 初始化Mutex对象
lk := sync.Mutex{}
// 加锁
lk.Lock()
// 处理业务逻辑
// 解锁
lk.Unlock()
例子:
package main
import (
"fmt"
"sync"
)
var count int = 0
func main() {
// 初始化锁
lk := sync.Mutex{}
done := make(chan bool)
for i:=0; i < 100; i++ {
// 并发的累加count
go func() {
// 加锁
lk.Lock()
// 延迟解锁
defer lk.Unlock()
// 处理业务逻辑
count++
done <- true
}()
}
for i:=0; i < 100; i++ {
<-done
}
fmt.Println(count)
}
2.RWMutex
RWMutex是读写互斥锁。该锁可以被同时多个读取者持有或唯一个写入者持有。RWMutex可以创建为其他结构体的字段;零值为解锁状态。RWMutex类型的锁也和线程无关,可以由不同的线程加读取锁/写入和解读取锁/写入锁。
基本用法:
// 初始化RWMutex对象
lk := sync.RWMutex{}
// 加写锁
lk.Lock()
// 处理业务逻辑
// 解除写锁
lk.Unlock()
// 加读锁
lk.RLock()
// 处理业务逻辑
// 解除读锁
lk.RUnlock
跟Mutex的区别就是锁的粒度更小了,区分为读锁和写锁,读写锁的互斥关系如下:
协程1 | 协程2 | 阻塞状态 |
---|---|---|
读锁 | 读锁 | 不阻塞 |
读锁 | 写锁 | 阻塞 |
写锁 | 写锁 | 阻塞 |
大家都加读锁的时候是不会阻塞的,其他情况就会议阻塞协程。