共享資源競争:
多個goroutine操作同一個共享資料,存在不安全。
i:=1
go func(){ //第一個Goroutine 我們叫他g1
if i>0{ //①第一次g1執行到這裡的時候,資源被g2搶走
i--
fmt.Pringtln(i) //輸出i=0
}
}// ③然後g1搶回資源 執行結束 此時i已經等于0
go func(){ //第二個Goroutine 我們叫他g2
if i>0{ //②g2執行到這裡的時候又被g1把資源搶走了
i-- //④由于g1執行完畢 現在就剩下g2了 ,g2順序執行,i--
fmt.Pringtln(i)//⑤ 此時輸出i已經變成-1了,按理論來說已經不滿足條件了,但是由于判斷已經完成了,是以g2輸出的是-1
}
}
一個共享資料比如i=1,被第一個Goroutien搶到了資源,條件是i>0,判斷成立,下面執行i--,然後列印i,但是在i>0完之後又被第二個Goroutine搶到,同樣執行判斷i>0條件成立同樣的 他也隻是執行了條件判斷,并沒有執行i--和列印,這樣就有兩個滿足條件的Goroutine了,第一個正常完成程式,正常輸出i的值,但是第二個由于資料已經變了,是以輸出的值是錯誤的。為了避免這種情況,我們就要給Goroutine加上互斥鎖,在一個Goroutine通路資料時,别人是不能通路的,隻有等通路完畢開鎖之後,其他人才能來通路。
上鎖:互斥鎖(開,關)
sync.Mutex
Lock(),UnLock()
我們來舉一個賣票的例子,一共100張票,4個視窗賣,每賣一張,總票數-1,如果在不上鎖的情況下,有可能最後會出現多賣出3張的情況,為了更好的展現賣出的過程,我再裡面加了睡眠。
package main
import (
"fmt"
"sync"
"math/rand"
"time"
)
//全局變量
var ticket2 = 10 // 100張票
var wg3 sync.WaitGroup
var matex sync.Mutex // 建立鎖頭
func main() {
/*
4個goroutine,模拟4個售票口,4個子程式操作同一個共享資料。
*/
wg3.Add(4)
go saleticket2s("售票口1") // g1,100
go saleticket2s("售票口2") // g2,100
go saleticket2s("售票口3") //g3,100
go saleticket2s("售票口4") //g4,100
wg3.Wait() // main要等待。。。
}
func saleticket2s(name string) {
rand.Seed(time.Now().UnixNano())
defer wg3.Done()
//for i:=1;i<=100;i++{
// fmt.Println(name,"售出:",i)
//}
for { //1, g1 ,g2,g3,g4
//上鎖, g2
matex.Lock()
if ticket2 > 0 { //g1,g3,g2,g4
//睡眠
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
// g1 ,g3, g2,g4
fmt.Println(name, "售出:", ticket2) // 1 , 0, -1 , -2
ticket2-- //0 , -1 ,-2 , -3
} else {
matex.Unlock()//條件不滿足,也要解鎖,結束循環
fmt.Println("售罄,沒有票了。。")
break
}
matex.Unlock()//解鎖
}
}