Mutex
- sync.Mutex为互斥锁,同一时间只能有一个goroutine获得互斥锁。
- 使用Lock()加锁,Unlock()解锁,加锁前不能解锁,加锁后不能继续加锁。
- 已经锁定的 Mutex 并不与特定的 goroutine 相关联,可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁。
- 适用于同一时间只能有一个goroutine访问资源的场景。
下面的代码如果不使用Mutex,输出的会是1 1 2 2 3 3而不是1 2 3 1 2 3。
package main
import (
"fmt"
"sync"
"time"
)
var (
mutex sync.Mutex
)
func print123(){
mutex.Lock()
defer mutex.Unlock()
for i:=0;i<3;i++{
fmt.Println(i+1)
time.Sleep(time.Millisecond*100)
}
}
func main(){
go print123()
go print123()
time.Sleep(time.Second*5)
}
RWMutex
- sync.RWMutex为读写锁,同一时间可以有多个goroutine获得读锁或者一个goroutine获得写锁。
- 使用Lock()加写锁,Unlock()解写锁,RLock()加读锁,RUnlock()解读锁,读锁可以加多个,解读锁的次数不能多于加读锁的次数。
- 适用于同一时间可以有多个goroutine对资源进行读操作或一个goroutine对资源进行写操作的场景。
- 读少写多的情况下使用Mutex,其它情况下RWMutex性能更好。
Map
Go内建的map不是线程安全的,所以之前都会使用加锁的方式控制对map的并发访问,而在新版本中可以使用sync.Map代替map+RWMutex,sync.Map相比后者有更好的性能,下面是sync.Map的基本使用方法:
package main
import (
"fmt"
"sync"
)
var (
players sync.Map
)
func main(){
//设置key对应的value
players.Store("xiao ming",100)
//返回key对应的valuee,value不存在时返回nil,false
if value,ok:=players.Load("xiao ming");ok{
fmt.Println(value)
}else{
fmt.Println("key:xiao ming does not exist!")
}
//如果key对应的value存在,则返回value和true
//如果key对应的value不存在,则将key对应的value设置为参数中的value,并返回value和false
if value,ok := players.LoadOrStore("xiao hong",120);ok{
fmt.Println(value)
}else{
fmt.Println("key:xiao hong does not exist,store it!")
}
//遍历map,函数返回false时停止遍历
players.Range(func(key,value interface{})bool{
fmt.Println(key,value)
return true
})
//删除key对应的value
players.Delete("xiao hong")
}
atomic
sync.atomic提供了对几种简单类型进行原子操作的函数,相比Mutex/RWMutex,其性能更好,临界区也更小。
有疑问加站长微信联系(非本文作者)