Go语言互斥锁和读写锁的用法(附带实例)
在 Go 语言提供的 sync 包中有两种锁类型,即互斥锁(sync.Mutex)和读写互斥锁(sync.RWMutex)。
其中,互斥锁比较简单,当一个协程获得互斥锁后,其他协程只能等这个协程释放互斥锁。
读写互斥锁则是经典的单写多读模型。读锁被占用时仅阻止写,但不阻止读。在写锁被占用的情况下,既阻止写,也组织读。
下例演示互斥锁的使用方法。
【实例】让两个协程依次打印数据。
声明互斥锁的全局变量 mutex,定义打印 3~5 的 printData() 函数,分别调用 Lock() 函数和 Unlock() 函数对 printData() 函数进行加锁、解锁处理。
在 main() 函数中,启动并发程序(即 printData() 函数),分别调用 Lock() 函数和 Unlock() 函数对 main() 函数进行加锁、解锁处理,以实现先由 main() 函数占用资源打印 0~2、待资源被释放后再由 printData() 函数打印 3~5 的目的。代码如下:
下例演示读写互斥锁(sync.RWMutex)的使用方法。
【实例 2】如何使用读写互斥锁:
代码如下:
其中,互斥锁比较简单,当一个协程获得互斥锁后,其他协程只能等这个协程释放互斥锁。
读写互斥锁则是经典的单写多读模型。读锁被占用时仅阻止写,但不阻止读。在写锁被占用的情况下,既阻止写,也组织读。
下例演示互斥锁的使用方法。
【实例】让两个协程依次打印数据。
声明互斥锁的全局变量 mutex,定义打印 3~5 的 printData() 函数,分别调用 Lock() 函数和 Unlock() 函数对 printData() 函数进行加锁、解锁处理。
在 main() 函数中,启动并发程序(即 printData() 函数),分别调用 Lock() 函数和 Unlock() 函数对 main() 函数进行加锁、解锁处理,以实现先由 main() 函数占用资源打印 0~2、待资源被释放后再由 printData() 函数打印 3~5 的目的。代码如下:
package main
import (
"fmt"
"sync"
"time"
)
var mutex sync.Mutex // 声明互斥锁的全局变量
func printData() {
mutex.Lock() // 加锁
for i := 3; i < 6; i+++ {
time.Sleep(1 * time.Second) // 每隔 1s 打印一个数字
fmt.Println(i)
}
mutex.Unlock() // 解锁
}
func main() {
go printData() // 启动并发程序
mutex.Lock() // 加锁
for i := 0; i < 3; i+++ {
time.Sleep(1 * time.Second) // 每隔 1s 打印一个数字
fmt.Println(i)
}
mutex.Unlock() // 解锁
time.Sleep(6 * time.Second) // 等待并发程序执行完成
}
运行结果如下:
0
1
2
3
4
5
下例演示读写互斥锁(sync.RWMutex)的使用方法。
【实例 2】如何使用读写互斥锁:
- 声明表示随机数的全局变量 numRand、读写互斥锁的全局变量 rw,以及同步等待组的全局变量 wg;
- 定义执行读操作的 read() 函数,使用 RLock() 函数和 RUnlock() 函数对其进行加锁、解锁处理,通过设置延时,打印执行读操作后的随机数;
- 定义执行写操作的 write() 函数,使用 Lock() 函数和 Unlock() 函数进行加锁、解锁处理,通过设置延时,打印执行写操作后的随机数;
- 在 main() 函数中,设置同步等待组,分别各执行 3 次 read() 函数和 write() 函数。
代码如下:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var numRand int // 声明表示随机数的全局变量
var rw sync.RWMutex // 声明读写互斥锁的全局变量
var wg sync.WaitGroup // 声明同步等待组的全局变量
func read(i int) {
rw.RLock() // 加锁
time.Sleep(time.Duration(i) * time.Second) // 设置延时
fmt.Printf("执行读操作,数据:%d\n", numRand)
rw.RUnlock() // 解锁
wg.Done()
}
func write(i int) {
rw.Lock() // 加锁处理
numRand = rand.Intn(100) // 100以内的随机数
time.Sleep(time.Duration(i) * time.Second) // 设置延时
fmt.Printf(100以内的随机数
fmt.Printf("执行写操作,数据:%d\n", numRand)
rw.Unlock() // 解锁处理
wg.Done()
}
func main() {
wg.Add(6) // 设置同步等待组
for i := 1; i < 4; i+++ {
go write(i) // 启动 3 次并发程序,即 write() 函数
}
for i := 3; i < 4; i+++ {
go read(i) // 启动 3 次并发程序,即 read() 函数
}
wg.Wait() // 等待同步等待组执行并发程序
}
运行结果如下(不唯一):
执行读操作,数据:0
执行写操作,数据:81
执行读操作,数据:81
执行读操作,数据:81
执行写操作,数据:87
执行写操作,数据:47
ICP备案:
公安联网备案: