go语言中有两种常见的锁机制,互斥锁,读写锁。
互斥锁
互斥锁比较暴力,当一个goroutine获得了互斥锁之后,其他的goroutine就只能够乖乖地等其解锁才能访问这个资源。
其中有两个公开的指针方法:
func (*Mutex) Lock
func (*Mutex) Unlock
这里借用一下之前文章《Go 临界资源的安全问题》中卖票的例子,加上互斥锁的代码如下:
package main
import (
"fmt"
"math/rand"
"sync"
"time"
)
var ticket = 10 //the amount of the total ticket is 100
//创建一个锁🔐对象
var mutex sync.Mutex
//创建一个同步等待组对象
var wg sync.WaitGroup
func main() {
wg.Add(4)
//这里启动4个goroutine模拟4个售票口 同时售票
go saleTickets("ticket window1")
go saleTickets("ticket window2")
go saleTickets("ticket window3")
go saleTickets("ticket window4")
//这里为了保证 主协程 最后执行完 先用sleep (当然,也可以用同步等待组、chanel实现)
//time.Sleep(10 * time.Second) 用同步等待组waitgroup代替sleep
wg.Wait()
}
func saleTickets(name string) {
rand.Seed(time.Now().UnixNano())
//票卖光,goroutine要结束的时候 需要把同步等待组的counter计数器-1
defer wg.Done()
for {
//上锁🔐
mutex.Lock()
if ticket > 0 {
time.Sleep(time.Duration(rand.Intn(1000)) * time.Millisecond)
fmt.Println(name, "saled: ", ticket)
ticket--
} else {
//条件不满足 也要解锁🔓
mutex.Unlock()
fmt.Println(name, "sorry tickets are sold out")
break
}
//🔓解锁
mutex.Unlock()
}
}
加上锁之后就不会出现卖出负票的情况了,结果如下:
ticket window4 saled: 10
ticket window4 saled: 9
ticket window2 saled: 8
ticket window3 saled: 7
ticket window1 saled: 6
ticket window4 saled: 5
ticket window2 saled: 4
ticket window3 saled: 3
ticket window1 saled: 2
ticket window4 saled: 1
ticket window2 sorry tickets are sold out
ticket window4 sorry tickets are sold out
ticket window1 sorry tickets are sold out
ticket window3 sorry tickets are sold out
需要注意的是:
- 一定要记得解锁,否则就会发生异常or死锁等问题
- 推荐使用defer语句来解锁
参考资料:bilibili
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。