背景
Google工程師Valentin Deleplace出了2道關於鎖的題目,拿出來和大家分享下。
題目1
// quiz_lock1.go
package main
import (
"fmt"
"sync"
)
func main() {
var m sync.Mutex
fmt.Print("1, ")
m.Lock()
m.Lock()
m.Unlock()
fmt.Println("2")
}
- A:
1, 2
- B:
1,
- C:
1, fatal error:......
- D: 編譯報錯
題目2
// quiz_lock2.go
package main
import (
"fmt"
"sync"
"time"
)
func main() {
var m sync.Mutex
fmt.Print("1, ")
m.Lock()
go func() {
time.Sleep(200 * time.Millisecond)
m.Unlock()
}()
m.Lock()
fmt.Println("2")
}
- A:
1, 2
- B:
1,
- C:
1, fatal error:......
- D: 編譯報錯
解析
Go語言裡的sync.Mutex和sync.RWMutex都是不可重入的,Go語言裡沒有可重入鎖(也叫遞迴鎖)。
如果mutex沒有釋放,在同一個goroutine就不能對這個mutex加2次鎖,否則第2次加鎖就會阻塞,如果沒有其它goroutine去釋放這個mutex,就會導致死鎖,出現runtime error: fatal error: all goroutines are asleep - deadlock!
。
同時,sync.Mutex和sync.RWMutex允許一個goroutine對其加鎖,其它goroutine對其解鎖,不要求加鎖和解鎖在同一個goroutine裡。
所以第一道題目的答案是C
,第二道題目的答案是A
。
思考題
// quiz_lock3.go
package main
import (
"fmt"
"sync"
)
var a sync.Mutex
func main() {
a.Lock()
fmt.Print("1, ")
a.Unlock()
fmt.Print("2, ")
a.Unlock()
fmt.Println("3")
}
- A:
1, 2, 3
- B:
1, 2, fatal error:......
- C:
1, 2
- D: 編譯報錯
想知道答案的可以給公眾號傳送訊息mutex
獲取答案。
總結
Go語言裡的鎖和C++,Java裡的不太一樣,給大家總結了以下注意事項
- Go的鎖是不可重入的,沒有遞迴鎖
- 允許一個goroutine加鎖,另一個goroutine解鎖,不要求加鎖和解鎖在同一個goroutine裡
- sync.Mutex的零值是沒有加鎖的Mutex,sync.RWMutex的零值是沒有加鎖的RWMutex
- 更多細節可以參考References裡Mutex和RWMutex的官方說明
開源地址
文章和示例程式碼開源在GitHub: Go語言初級、中級和高階教程。
公眾號:coding進階。關注公眾號可以獲取最新Go面試題和技術棧。
個人網站:Jincheng's Blog。
知乎:無忌。