【Golang】关于Go语言中的锁
在 Golang 里有专门的方法来实现锁,就是 sync 包,这个包有两个很重要的锁类型
一个叫 Mutex, 利用它可以实现互斥锁。一个叫 RWMutex,利用它可以实现读写锁。
互斥锁:Mutex
概念:使用互斥锁(Mutex,全称 mutual exclusion)是为了来保护一个资源不会因为并发操作而引起冲突导致数据不准确。
使用Mutext锁虽然很简单,但是仍然有几点需要注意:
- 同协程中,不要在尚未解锁时再次使用加锁
- 同协程中,不要对已解锁的锁再次解锁
- 加了锁后,别忘了解锁,必要时使用defer语句
读写锁:RWMutex
概念:是最简单的一种锁类型,他提供了一个傻瓜式的操作,加锁解锁加锁解锁,让你不需要再考虑其他的。简单 同时意味着在某些特殊情况下有可能会造成时间上的浪费,导致程序性能低下。另外RWMutex提供了两种锁,每种锁分别对应两种方法,为了避免死锁,两个方法应成对出现,必要时请求使用defer
- 读锁:调用RLock方法开启锁,调用RUlock释放锁。且:
读写锁中读锁没有排它性, 即读锁没有释放, 读锁还能申请
- 写锁:调用Lock方法开启锁,调用Unlock释放锁。且:
读写锁中写锁具有排它性, 即如果写锁没有释放, 读锁和写锁申请时, 会无限等待(死锁)
关键点:
- 为了保证数据的安全,它规定了当有人还在读取数据(即读锁占用)时,不允许有人更新这个数据(即写锁会阻塞)
- 为了保证数据的安全,多个人(协程)读取数据时(拥有读锁)时,互不影响不会造成阻塞,它不会想Mutext那样只允许有一个人(协程)读取同一个数据
代码:
package main
import (
"fmt"
"sync"
)
var lck sync.RWMutex
func Me() {
lck.Lock()
defer lck.Unlock()
fmt.Println("写作业")
watch()
}
func watch() {
lck.RLock()
defer lck.RUnlock()
fmt.Println("看电视")
}
// WriteLockExclusive 读写锁中写锁具有排它性, 即如果写锁没有释放, 读锁和写锁申请时, 会无限等待(死锁)
func WriteLockExclusive() {
fmt.Println("我很菜, 我能边写作业, 边看电视吗")
Me()
fmt.Println("我能")
}
func She() {
lck.RLock()
defer lck.RUnlock()
fmt.Println("写作业")
sheWatch()
}
func sheWatch() {
lck.RLock()
defer lck.RUnlock()
fmt.Println("看电视")
}
// ReadLockSharing 读写锁中读锁没有排它性, 即读锁没有释放, 读锁还能申请
func ReadLockSharing() {
fmt.Println("她很牛逼, 她能边写作业, 边看电视吗")
She()
fmt.Println("她能")
}
func main() {
ReadLockSharing()
}