在golang中,实现了两种锁:
- Mutex,互斥锁
- RWMutex:读写锁,RWMutex基于Mutex实现
Mutex(互斥锁)
- Mutex为互斥锁,Lock()加锁,Unlock()解锁
- 在一个goroutine获得Mutex之后,其他goroutine只能等到这个goroutine释放该Mutex
- 使用Lock()加锁之后,不能继续对其加锁,知道利用Unlock()解锁之后才能解锁
- 在Lock()之前使用Unlock()会导致panic异常
- 已经锁定的Mutex并不与特定的goroutine相关联,这样可以利用一个goroutine对其加锁,再利用其他groutine对其解锁
- 适用于读写不确定,并且只有一个读或者写的场景
加锁和解锁示例
package main
import (
"time"
"fmt"
"sync"
)
func main() {
var mutex sync.Mutex
fmt.Println("Lock the lock")
mutex.Lock()
fmt.Println("The lock is locked")
channels := make([]chan int, 4)
for i := 0; i < 4; i++ {
channels[i] = make(chan int)
go func(i int, c chan int) {
fmt.Println("Not lock: ", i)
mutex.Lock()
fmt.Println("Locked: ", i)
time.Sleep(time.Second)
fmt.Println("Unlock the lock: ", i)
mutex.Unlock()
c <- i
}(i, channels[i])
}
time.Sleep(time.Second)
fmt.Println("Unlock the main goroutine lock")
mutex.Unlock()
time.Sleep(time.Second)
for _, c := range channels {
<-c
}
}
// 程序输出
Lock the lock
The lock is locked
Not lock: 1
Not lock: 0
Not lock: 2
Not lock: 3
Unlock the main goroutine lock
Locked: 1
Unlock the lock: 1
Locked: 0
Unlock the lock: 0
Locked: 2
Unlock the lock: 2
Locked: 3
Unlock the lock: 3
在解锁之前加锁会导致死锁
package main
import (
"fmt"
"sync"
)
func main(){
var mutex sync.Mutex
mutex.Lock()
fmt.Println("Locked")
mutex.Lock()
}
//程序输出
Locked
fatal error: all goroutines are asleep - deadlock!
RWMutex(读写锁)
- RWMutex是单写多读锁,该锁可以加多个读锁或者一个写锁
- 读锁占用的情况下会阻止写,不会阻止读,多个goroutine可以同时获取读锁
- 写锁会阻止其他goroutine(无论读和写进来)进来,整个锁由该goroutine 独占
- 适用于读多写少的场景
写锁:Lock() 和 Unlock()
- Lock()加写锁,Unlock()解写锁
- 如果在加写锁之前已经由其他的读锁或者写锁,则Lock()会阻塞直到该锁可用。已经阻塞的Lock()调用会从获得的锁中排除新的读取器,即写锁的权限高于读锁,有写锁时优先进行写锁定
-
读锁:RLock() 和 RUnlock()
Rlock()加读锁,RUnlock()解读锁
- RLock()加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加载多个
- RUnlock()解读锁,Runlock()撤销单次RLock()调用,对于其他同时存在的读锁则没有效果
- 在没有读锁的情况下调用Runlock()会导致panic错误
下面展示一下我们的写锁:
// 在这里,我们使用一个
type Handler struct {
mx sync.RWMutex
lastActive time.Time
}
func (h *Handler) Run() {
h.mx.Lock()
{
h.lastActive = time.Now()
}
h.mx.Unlock()
}
总结一下:互斥锁定就是单读单写,只能有一种状态;而读写锁则是可以用读锁和写锁,写锁的优先级别高于读锁。