1.互斥锁
goroutinesyncMutex
var x int64
var wg sync.WaitGroup
var lock sync.Mutex
func add() {
for i := 0; i < 5000; i++ {
lock.Lock() // 加锁
x = x + 1
lock.Unlock() // 解锁
}
wg.Done()
}
func main() {
wg.Add(2)
go add()
go add()
wg.Wait()
fmt.Println(x)
}
结果永远是10000。 对公共资源操作时,应该加锁
goroutinegoroutinegoroutinegoroutine
模拟读多写少的一个场景
var (
x = 0
wg sync.WaitGroup
lock sync.Mutex
)
func read () {
defer wg.Done()
lock.Lock()
fmt.Println(x)
time.Sleep(time.Millisecond) 读需要1毫秒
lock.Unlock()
}
func write() {
defer wg.Done()
lock.Lock()
x ++
lock.Unlock()
time.Sleep(time.Millisecond * 5) 写需要5毫秒
}
func main() {
start := time.Now()
for i:= 0; i<10 ; i++ {
go write()
wg.Add(1)
}
for i:= 0; i<1000 ; i++ {
go read()
wg.Add(1)
}
wg.Wait()
fmt.Println(time.Since(start)) 15.516195s
}
互斥锁,在读的时候,也会阻塞下一个读线程,这样效率很低。
2.读写互斥锁
普通锁是 sync.Mutex
读写锁是 sync.RWMutex
syncRWMutex
goroutinegoroutinegoroutine
RWMutex提供了四个方法:
func (*RWMutex) Lock // 写锁定
func (*RWMutex) Unlock // 写解锁
func (*RWMutex) RLock // 读锁定
func (*RWMutex) RUnlock // 读解锁
读写锁示例:
var (
x = 0
wg sync.WaitGroup
lock sync.RWMutex
)
func read () {
defer wg.Done()
lock.RLock() 加读锁
fmt.Println(x)
time.Sleep(time.Millisecond)
lock.RUnlock() 解读锁
}
func write() {
defer wg.Done() 加写锁
lock.Lock()
x ++
lock.Unlock() 解写锁
time.Sleep(time.Millisecond * 5)
}
func main() {
start := time.Now()
for i:= 0; i<10 ; i++ {
go write()
wg.Add(1)
}
for i:= 0; i<1000 ; i++ {
go read()
wg.Add(1)
}
wg.Wait()
fmt.Println(time.Since(start)) 20.0658ms,速度和互斥锁差别非常大
}
需要注意的是读写锁非常适合读多写少的场景,如果读和写的操作差别不大,读写锁的优势就发挥不出来。