锁的种类
-
互斥锁(
sync.Mutex
) -
读写互斥锁(
sync.RWMutex
)
Go提供的函数
go
的sync
包下提供了两种类型:
-
sync.Mutex
-
sync.RWMutex
Mutex
Mutex的概念
最简单的锁定
特点:
当一个goroutine
获得Mutex
后,其他goroutine
只能等待该goroutine
释放该Mutex
RWMutex
RWMutex的概念
单写多读模型
概念:
-
读锁占用的情况下,阻止写不阻止读
-
写锁会阻止其他的读、写过程
示例代码:
package main
import (
"fmt"
"sync"
)
/*
设计Mutex的实例
*/
// 声明变量
var (
// 声明逻辑中使用到的变量
countNo2 int
// 声明变量的互斥锁
countGuard sync.Mutex
)
// 获取变量
func GetCount() int {
// 锁定
/*
对 countGuard 互斥量进行加锁。一旦 countGuard 发生加锁,如果另外一个 goroutine 尝试继续加锁时将会发生阻塞,直到这个 countGuard 被解锁。
*/
countGuard.Lock()
// 函数接触时的处理
defer countGuard.Unlock()
// 返回变量
return countNo2
}
// 设置变量
func SetCount(c int) {
// 上锁
countGuard.Lock()
// 赋值
countNo2 = c
// 解锁
countGuard.Unlock()
}
// main函数中调用
func main() {
// 并发安全设置
SetCount(1)
// 打印并发安全的获取
fmt.Println(GetCount())
}
在读多写少的环境可以优先使用读写互斥锁(RWMutex
),因为它更高效.
var (
// 声明逻辑中使用到的变量
countNo2 int
// 声明变量的互斥锁
countGuard sync.RWMutex
)
// 获取变量
func GetCount() int {
// 锁定
/*
对 countGuard 互斥量进行加锁。一旦 countGuard 发生加锁,如果另外一个 goroutine 尝试继续加锁时将会发生阻塞,直到这个 countGuard 被解锁。
*/
//countGuard.Lock()
// 使用读写互斥锁
countGuard.RLock()
// 函数接触时的处理
/*
与读模式加锁对应的,使用读模式解锁。
*/
defer countGuard.RUnlock()
// 返回变量
return countNo2
}
总结
RWMutex
类型其实组合了Mutex
n
共同点:
任何一个Lock()
或RLock()
均需要保证对应有Unlock()
或 RUnlock()
调用与之对应,否则可能导致等待该锁的所有 goroutine