几个demo来学习和演示sync包的使用。
go
package lockdemo
import (
"fmt"
"sync"
"time"
)
var sum int = 0
var lock sync.Mutex
var rwlock sync.RWMutex
var wg sync.WaitGroup
func add(i int) {
lock.Lock()
defer lock.Unlock()
sum += i
}
func readSum() int {
//只获取读锁
rwlock.RLock()
defer rwlock.RUnlock()
b := sum
return b
}
func run() {
//因为要监控110个协程,所以设置计数器为110
wg.Add(110)
for i := 0; i < 100; i++ {
go func() {
//计数器值减1
defer wg.Done()
add(10)
}()
}
for i := 0; i < 10; i++ {
go func() {
//计数器值减1
defer wg.Done()
fmt.Println("和为:", readSum())
}()
}
//一直等待,只要计数器值为0
wg.Wait()
}
// 只执行一次
// 适用于创建某个对象的单例、只加载一次的资源等只执行一次的场景
func doOnce() {
var once sync.Once
onceBody := func() {
fmt.Println("Only once")
}
//用于等待协程执行完毕
done := make(chan bool)
//启动10个协程执行once.Do(onceBody)
for i := 0; i < 10; i++ {
go func() {
//把要执行的函数(方法)作为参数传给once.Do方法即可
once.Do(onceBody)
done <- true
}()
}
for i := 0; i < 10; i++ {
<-done
}
}
// 10个人赛跑,1个裁判发号施令
// 适用于需要等待多个协程完成某个任务的场景
func race() {
cond := sync.NewCond(&sync.Mutex{})
var wg sync.WaitGroup
wg.Add(11)
for i := 0; i < 10; i++ {
go func(num int) {
defer wg.Done()
fmt.Println(num, "号已经就位")
cond.L.Lock()
cond.Wait() //等待发令枪响
fmt.Println(num, "号开始跑......")
cond.L.Unlock()
}(i)
}
//等待所有goroutine都进入wait状态
time.Sleep(2 * time.Second)
go func() {
defer wg.Done()
fmt.Println("裁判已经就位,准备发令枪")
fmt.Println("比赛开始,大家准备跑")
cond.Broadcast() //发令枪响,唤起所有的协程、Signal,唤醒一个等待时间最长的协程。
}()
//防止函数提前返回退出
wg.Wait()
}