sync.Mutexsync.RWMutex
RLock()叫读锁。它不是绝对锁,可以有多个读者同时获取此锁
Lock()叫写锁,它是个绝对锁,一旦某人拿了这个锁,别人就不能再获取此锁了。
2、sync.WaitGroup
https://blog.csdn.net/u013474436/article/details/88749749
经常会看到如下代码
func main(){
for i := 0; i < 100; i++ {
go fmt.Println(i)
}
time.Sleep(time.Second)
}
time.Sleep()time.Sleep()
time.Sleep()
可以考虑使用管道来完成上述操作:
func main(){
c := make(chan bool, 100)
for i := 0; i < 100; i ++ {
go func(num int){
fmt.Println(num)
c <- true
}(i)
}
for i := 0; i < 100; i++ {
<- c
}
}
首先可以肯定的是使用管道可以达到我们的目的,且不仅能达到,还能十分完美的达到目的
但是管道在这里显得有些大材小用了,因为它被设计出来不仅仅只是在这里用作同步处理,在这里使用管道实际上是不合适的。而且假设我们有一万、十万甚至更多的for循环,也要申请同样数量大小的管道出来,对内存也是不小的开销。
sync.WaitGroup
WaitGroupAdd(),Done(),Wait()Add(n)nDone()-1wait()0
WaitGroup
func main(){
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i++{
go func(num int){
fmt.Println(i)
wg.Done()
}(i)
}
}
100for1Wait()wg100forWaitGroup
注意事项
1.计数器不能设置为负值
Add()wg
panic: sync: negative WaitGroup counter
goroutine 1 [running]:
sync.(*WaitGroup).Add(0xc042008230, 0xffffffffffffff9c)
D:/Go/src/sync/waitgroup.go:75 +0x1d0
main.main()
D:/code/go/src/test-src/2-Package/sync/waitgroup/main.go:10 +0x54
Done()
2.WaitGroup对象不是一个引用类型
func main(){
wg := sync.WaitGroup{}
wg.Add(100)
for i := 0; i < 100; i ++ {
go f(i, &wg)
}
wg.Wait()
}
// 一定要通过指针传值,不然进程会进入死锁状态
func f(i int, wg *sync.WaitGroup){
fmt.Println(i)
wg.Done()
}
3、sync.Mutex
Mutex为互斥锁,Lock()加锁,Unlock()解锁,使用Lock()加锁后,不能再次对其进行加锁,直到利用Unlock()解锁后才能再次加锁,适用于读写不确定的场景,即读写次数没有明显的区别,并且只允许一个读或者写的场景,所以该锁也叫全局锁
已经锁定的Mutex并不与特定的goroutine关联,这样可以利用一个goroutine加锁,再利用其它goroutine对其解锁
package main
import (
"fmt"
"runtime"
"sync"
)
type Counter struct {
mu sync.Mutex
x int64
}
func (c *Counter) Inc() {
c.mu.Lock()
defer c.mu.Unlock()
c.x++
}
func main() {
runtime.GOMAXPROCS(runtime.NumCPU())
c := Counter{}
var wait sync.WaitGroup
wait.Add(4)
for k := 4; k > 0; k-- {
go func() {
for i := 2500000; i > 0; i-- {
c.Inc()
}
wait.Done()
}()
}
wait.Wait()
fmt.Println(c.x)
}
4、sync.RWMutex
RWMutex是一个读写锁,该锁可以加多个读锁或者一个写锁,其经常用于读次数远远多于写次数的场景
- func(rw *RWMutex) Lock() 写锁,如果在添加写锁之前已经有其他的读锁和写锁,则lock就会阻塞直到该锁可用,已阻塞的Lock调用会从获得的锁中排除新的读取器