面试题答案
一键面试模拟死锁代码
package main
import (
"fmt"
"sync"
)
var (
mutexA sync.Mutex
mutexB sync.Mutex
)
func goroutineA(wg *sync.WaitGroup) {
defer wg.Done()
mutexA.Lock()
fmt.Println("goroutine A acquired mutexA")
mutexB.Lock()
fmt.Println("goroutine A acquired mutexB")
mutexB.Unlock()
mutexA.Unlock()
}
func goroutineB(wg *sync.WaitGroup) {
defer wg.Done()
mutexB.Lock()
fmt.Println("goroutine B acquired mutexB")
mutexA.Lock()
fmt.Println("goroutine B acquired mutexA")
mutexA.Unlock()
mutexB.Unlock()
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go goroutineA(&wg)
go goroutineB(&wg)
wg.Wait()
}
预防死锁方案
通过调整获取锁的顺序来预防死锁,比如让两个goroutine都按照相同的顺序获取锁。
调整后代码
package main
import (
"fmt"
"sync"
)
var (
mutexA sync.Mutex
mutexB sync.Mutex
)
func goroutineA(wg *sync.WaitGroup) {
defer wg.Done()
mutexA.Lock()
fmt.Println("goroutine A acquired mutexA")
mutexB.Lock()
fmt.Println("goroutine A acquired mutexB")
mutexB.Unlock()
mutexA.Unlock()
}
func goroutineB(wg *sync.WaitGroup) {
defer wg.Done()
mutexA.Lock()
fmt.Println("goroutine B acquired mutexA")
mutexB.Lock()
fmt.Println("goroutine B acquired mutexB")
mutexB.Unlock()
mutexA.Unlock()
}
func main() {
var wg sync.WaitGroup
wg.Add(2)
go goroutineA(&wg)
go goroutineB(&wg)
wg.Wait()
}
在上述修改后的代码中,goroutineA
和goroutineB
都先获取mutexA
,再获取mutexB
,这样就避免了死锁的发生。