1. WaitGroup等待组
WaitGroup通过一个计数器counter来让主协程在还有子协程运行的时候进行等待
- wg.Add(num)函数可以让counter的值加上具体数值
- wg.Wait()函数可以让主协程进入阻塞状态
- wg. Done()函数可以让counter的值减一,相当于Add(-1)
package main
import (
"fmt"
"sync"
)
var wg sync.WaitGroup
func main() {
wg.Add(2)
go func1()
go func2()
fmt.Println("WaitGroup进入阻塞...")
wg.Wait()
fmt.Println("WaitGroup结束阻塞...")
}
func func1() {
for i := 0; i < 10; i++ {
fmt.Println("func1执行... ", i)
}
wg.Done()
}
func func2() {
defer wg.Done()
for i := 0; i < 10; i++ {
fmt.Println("\tfunc2执行... ", i)
}
}
2. Mutex互斥锁
通过给临界资源加锁,以让多个协程互斥访问临界资源。
- mutex.Lock()函数给资源加锁
- mutex.Unlock()函数给资源解锁
package main
import (
"fmt"
"sync"
)
var ticktsNum = 10
var wg sync.WaitGroup
var mutex sync.Mutex
func main() {
wg.Add(4)
go saleTickts(1)
go saleTickts(2)
go saleTickts(3)
go saleTickts(4)
wg.Wait()
}
func saleTickts(window int) {
defer wg.Done()
for {
mutex.Lock()
if ticktsNum > 0 {
fmt.Printf("窗口%d售卖,剩余票%d张\n", window, ticktsNum)
ticktsNum--
mutex.Unlock()
} else {
fmt.Printf("窗口%d售卖,票数不足\n", window)
mutex.Unlock()
break
}
}
}
3. RWMutex读写锁
Go语言包中的sync
包提供了两种锁类型:sync.Mutex
和sync.RWMutex
。其中RWMutex
是基于Mutex
实现的,只读锁的实现使用类似引用计数器的功能。读写锁与互斥锁的最大不同是它可以针对读操作或写操作单独加锁,性能更高。
- 多个协程可以同时读
- 在一个协程写的时候,其他协程读写操作都不能进行
package main
import (
"fmt"
"sync"
"time"
)
var wg sync.WaitGroup
var rwMutex sync.RWMutex
func main() {
wg.Add(3)
go readData(1)
go readData(2)
go readData(3)
wg.Wait()
fmt.Println("读锁测试结束\n")
time.Sleep(3 * time.Second)
wg.Add(3)
go writeData(1)
go readData(2)
go writeData(3)
wg.Wait()
fmt.Println("写锁测试结束")
}
func readData(num int) {
defer wg.Done()
fmt.Println(num, "开始读")
rwMutex.RLock()
fmt.Println(num, "正在读...")
time.Sleep(2 * time.Second)
rwMutex.RUnlock()
fmt.Println(num, "读结束,释放锁")
}
func writeData(num int) {
defer wg.Done()
fmt.Println(num, "开始写")
rwMutex.Lock()
fmt.Println(num, "正在写...")
time.Sleep(2 * time.Second)
rwMutex.Unlock()
fmt.Println(num, "写结束,释放锁")
}