背景
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。
知乎:无忌。
References
- https://github.com/jincheng9/…
- https://twitter.com/val_delep…
- https://twitter.com/val_delep…
- https://pkg.go.dev/sync@go1.1…
- https://pkg.go.dev/sync@go1.1…