先来看一个简单的例子,在不运行的前提下猜测结果是什么
这里模仿两个人同时刷卡的操作,猜测最后剩余多少钱
package main
import (
"time"
"fmt"
)
type Account struct {
money int
}
func (a *Account)DoPre() {
time.Sleep(time.Second) // 模仿银行进行检测
}
func (a *Account)GetGongzi(n int) {
a.money += n
}
func (a *Account) GiveWife(n int) {
if a.money > n {
a.DoPre()
a.money -= n
}
}
func (a *Account)Buy(n int) {
if a.money > n {
a.DoPre()
a.money -= n
}
}
func (a *Account) Left() int {
return a.money
}
func main() {
var account Account
account.GetGongzi(10)
go account.GiveWife(6) // 媳妇花6块
go account.Buy(5) // 同时自己花5块
time.Sleep(2 * time.Second) // 等待程序全部执行完毕
fmt.Println(account.Left())
}
结果为-1.
是不是感觉很费解。原因是当媳妇和自己在花钱的时候,同时抢到了相同的工资数(我们启动了2个协程),经过判断都成立,则进入sleep 1秒钟。 这时无论如何都会减去该花的钱。所以最后结果为 -1.
解决办法,为数据加锁,使其只有一人操作数据。
当然,解决的办法有很多种,这只是go里面比较好的解决办法
sync.Mutex
package main
import (
"time"
"fmt"
"sync"
)
type Account struct {
flag sync.Mutex // 使用一种复式变量, 只有一个人锁住,其他人就会sleep 直到解锁
money int
}
func (a *Account)DoPre() {
time.Sleep(time.Second) // 模仿银行进行检测
}
func (a *Account)GetGongzi(n int) {
a.money += n
}
func (a *Account) GiveWife(n int) {
a.flag.Lock() // 锁住
if a.money > n {
a.DoPre()
a.money -= n
}
a.flag.Unlock() // 释放锁
}
func (a *Account)Buy(n int) {
a.flag.Lock()
if a.money > n {
a.DoPre()
a.money -= n
}
a.flag.Unlock()
}
func (a *Account) Left() int {
return a.money
}
func main() {
var account Account
account.GetGongzi(10)
go account.GiveWife(6) // 媳妇花6块
go account.Buy(5) // 同时自己花5块
time.Sleep(2 * time.Second) // 等待程序全部执行完毕
fmt.Println(account.Left())
}
这样结果就合乎逻辑了!!!