Go语言协程并发---互斥锁sync.Mutex
package main import ( "fmt" "sync" "time" ) /* mt.Lock() 抢锁 一次只能被一个协程锁住 其余想要抢到这把锁的协程阻塞等待至前面的协程将锁释放 mt.Lock()的可能性有两种: ①抢到锁,继续向下执行 ②没抢到,阻塞等待至前面的协程将锁释放 ------------------------------------------- mt.Unlock() 解锁 锁一旦释放,其他抢这把锁的协程就会得到抢锁机会 */ func main() { //声明同步锁 var mt sync.Mutex var wg sync.WaitGroup var money = 2000 for i := 0; i < 10; i++ { wg.Add(1) go func(index int) { fmt.Printf("协程%d开始抢锁\n",index) //抢锁,如果成功,继续向下执行,否则阻塞等待至抢到为止(抢到的人不释放,你就一直阻塞) //所有抢锁的协程都是资源竞争者 mt.Lock() /*抢锁成功以后执行对数据的访问*/ fmt.Printf("协程%d抢锁成功!\n",index) fmt.Printf("协程%d开始操作数据!\n",index) for j := 0; j < 10000; j++ { money +=1 } <-time.After(2*time.Second) fmt.Printf("协程%d将锁释放!\n",index) //数据操作完毕,将锁释放 mt.Unlock() wg.Done() }(i) } wg.Wait() fmt.Println(money) }
一个互斥锁的小案例:
package main import ( "fmt" "sync" "time" ) /* 银行账户案例 ·创建银行类账户 ·存取款方式需要并发安全(不允许并发访问余额) ·查询余额和打印流水可以并发操作 ·创建账户实例,并发执行存取款,查询余额,打印流水操作 */ type Account struct{ money int //账户的互斥锁 mt sync.Mutex } /* 存钱:必须保证并发安全,不允许并发操作 */ func (a *Account)SaveMoney(n int) { //必须先抢到互斥锁 a.mt.Lock() fmt.Println("SaveMoney开始") <-time.After(3*time.Second) a.money += n fmt.Println("SaveMoney结束") //将锁释放 a.mt.Unlock() } /* 取钱:必须保证并发安全,不允许并发操作 */ func (a *Account)GetMoney(n int) { //必须先抢到互斥锁 a.mt.Lock() fmt.Println("GetMoney开始") <-time.After(3*time.Second) a.money -= n fmt.Println("GetMoney结束") //将锁释放 a.mt.Unlock() } /*查询余额:可以并发执行*/ func (a *Account)Query() { fmt.Println("Query开始") <-time.After(3*time.Second) fmt.Println("当前余额:",a.money) fmt.Println("Query结束") } ///*打印流水:可以并发执行*/ //func (a *Account)PrintHistory() { // fmt.Println("PrintHistory开始") // <-time.After(3*time.Second) // fmt.Println("打印流水") // fmt.Println("PrintHistory结束") //} func main() { var wg sync.WaitGroup account := &Account{10000, sync.Mutex{}} for i := 0; i < 3; i++ { wg.Add(1) go func() { account.SaveMoney(100) wg.Done() }() } for i := 0; i < 3; i++ { wg.Add(1) go func() { account.GetMoney(100) wg.Done() }() } for i := 0; i < 3; i++ { wg.Add(1) go func() { account.Query() wg.Done() }() } //for i := 0; i < 3; i++ { // wg.Add(1) // go func() { // account.PrintHistory() // wg.Done() // }() //} wg.Wait() fmt.Println("main over") }