本文摘自网络,作者,侵删。
前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html,
接下来要说的是golang的锁的使用场景主要涉及到哪些?读写锁为什么会比普通锁快。
一、什么场景下需要用到锁
当程序中就一个线程的时候,是不需要加锁的,但是通常实际的代码不会只是单线程,有可能是多个线程同时访问公共资源,所以这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢?
1. 多个线程在读相同的数据时
2. 多个线程在写相同的数据时
3. 同一个资源,有读又有写时
二、Go 锁分为两种:
互斥锁 (sync.Mutex)
读写锁 (sync.RWMutex 底层依赖Mutex实现 )
互斥锁是并发程序对公共资源访问限制最常见的方式。在Go中,sync.Mutex 提供了互斥锁的实现。
当一个goroutine获得了Mutex后,其他goroutine只能等待,除非该goroutine释放这个Mutex。
互斥锁结构:
type Mutex struct { state int32 sema uint32}
1. 锁定状态值为1,未锁定状态锁为 0 。
2. Lock()加锁、Unlock解锁。
读写锁则是对读写操作进行加锁。需要注意的是多个读操作之间不存在互斥关系,这样提高了对共享资源的访问效率。
Go中读写锁由 sync.RWMutex 提供,RWMutex在读锁占用的情况下,会阻止写,但不阻止读。RWMutex在写锁占用情况下,会阻止任何其他goroutine(无论读和写)进来,整个锁相当于由该goroutine独占。
读写锁结构:
type RWMutex struct { w Mutex // held if there are pending writers writerSem uint32 // semaphore for writers to wait for completing readers readerSem uint32 // semaphore for readers to wait for completing writers readerCount int32 // number of pending readers readerWait int32 // number of departing readers}
1. RWMutex是单写多读锁,该锁可以加多个读锁或者一个写锁。
2. 读锁占用的情况会阻止写,不会阻止读,多个goroutine可以同时获取读锁。
3. 写锁会阻止其他gorotine不论读或者写进来,整个锁由写锁goroutine占用 与第一条共用示范代码
4. 适用于读多写少的场景
三、如何使用互斥锁
Mutex为互斥锁,Lock() 加锁,Unlock() 解锁,使用Lock() 加锁后,便不能再次对其进行加锁,直到利用Unlock()解锁对其解锁后,才能再次加锁.适用于读写不确定场景,即读写次数没有明显的区别,并且只允许只有一个读或者写的场景,所以该锁叶叫做全局锁。
互斥锁只能锁定一次,当在解锁之前再次进行加锁,便会无法加锁。如果在加锁前解锁,便会报错"panic: sync: unlock of unlocked mutex"。
package main
import ("fmt"
"sync"
)
var (
count int
lock sync.Mutex
)
func main() {
for i := 0; i < 2; i++ {
go func() {
for i := 1000000; i > 0; i-- {
lock.Lock()
count ++
lock.Unlock()
}
fmt.Println(count)
}()
}
fmt.Scanf("\n") //等待子线程全部结束
}
运行结果:
1952533
2000000 //最后的线程打印输出
对于上面的程序,a作为一个公共的资源,所以对a的改变、读写等操作都需要加锁。
相关阅读 >>
Golang一行代码把array/slice转成逗号分隔的字符串
Golang网络数据传输过程中的binary.read与unsafe.pointer指针强转分析
更多相关阅读请进入《Go》频道 >>

Go语言101
一个与时俱进的Go编程知识库。