package main
funcmain(){
ch :=make(chanint)
ch <-789// 执行完后,channel的写端阻塞,后续的代码都不会执行,导致死锁
num :=<-ch
fmt.Println("num = ", num)}
2 - go程间channel访问顺序导致死锁
使用channel一端读(写), 要保证另一端写(读)操作,同时有机会执行;否则死锁
package main
funcmain(){
ch :=make(chanint)
num :=<-ch // 此时主go程已经阻塞,后续代码都不会执行
fmt.Println("num = ", num)gofunc(){
ch <-789}()}
3 - 多go程,多channel交叉死锁
Ago程,掌握M的同时,尝试拿N; Bgo程,掌握N的同时尝试拿M
package main
funcmain(){
ch1 :=make(chanint)
ch2 :=make(chanint)gofunc(){// 子for{select{case num :=<-ch1:
ch2 <- num
}}}()for{select{case num :=<-ch2:
ch1 <- num
}}}
package main
import("fmt""math/rand""sync""time")var rwMutex sync.RWMutex // 锁只有一把, 2个属性 r wfuncreadGo(in <-chanint, idx int){for{
rwMutex.RLock()// 以读模式加锁
num :=<-in
fmt.Printf("----%dth 读 go程,读出:%d\n", idx, num)
rwMutex.RUnlock()// 以读模式解锁}}funcwriteGo(out chan<-int, idx int){for{// 生成随机数
num := rand.Intn(1000)
rwMutex.Lock()// 以写模式加锁
out <- num
fmt.Printf("%dth 写go程,写入:%d\n", idx, num)
time.Sleep(time.Millisecond *300)// 放大实验现象
rwMutex.Unlock()}}funcmain(){// 播种随机数种子
rand.Seed(time.Now().UnixNano())
ch :=make(chanint)// 用于 数据传递的 channelfor i :=0; i <5; i++{goreadGo(ch, i+1)}for i :=0; i <5; i++{gowriteGo(ch, i+1)}for{}}
隐性死锁的解决方案:不混用读写锁和channel,要么只使用读写锁,要么只使用channel
读写锁-rwlock实现
package main
import("fmt""math/rand""sync""time")var rwMutex sync.RWMutex // 锁只有一把, 2 个属性 r wvar value int// 定义全局变量,模拟共享数据funcreadGo(idx int){for{
rwMutex.RLock()// 以读模式加锁
num := value
fmt.Printf("----%dth 读 go程,读出:%d\n", idx, num)
rwMutex.RUnlock()// 以读模式解锁
time.Sleep(time.Second)}}funcwriteGo(idx int){for{// 生成随机数
num := rand.Intn(1000)
rwMutex.Lock()// 以写模式加锁
value = num
fmt.Printf("%dth 写go程,写入:%d\n", idx, num)
time.Sleep(time.Millisecond *300)// 放大实验现象
rwMutex.Unlock()}}funcmain(){// 播种随机数种子
rand.Seed(time.Now().UnixNano())for i :=0; i <5; i++{// 5 个 读 go 程goreadGo(i +1)}for i :=0; i <5; i++{//gowriteGo(i +1)}for{}}
读写锁-channel实现:实际上Go语言设计的时候就希望通过chan替代锁
package main
import("fmt""math/rand""time")funcreadGo(in <-chanint, idx int){for{
num :=<-in // 从 channel 中读取数据
fmt.Printf("----%dth 读 go程,读出:%d\n", idx, num)
time.Sleep(time.Second)}}funcwriteGo(out chan<-int, idx int){for{// 生成随机数
num := rand.Intn(1000)
out <- num // 写入channel
fmt.Printf("%dth 写go程,写入:%d\n", idx, num)
time.Sleep(time.Millisecond *300)// 放大实验现象}}funcmain(){// 播种随机数种子
rand.Seed(time.Now().UnixNano())
ch :=make(chanint)for i :=0; i <5; i++{// 5 个 读 go 程goreadGo(ch, i+1)}for i :=0; i <5; i++{//gowriteGo(ch, i+1)}for{}}