go语言并发之锁的基操

go语言除了使用goroutine和channel这种CSP模型,也支持传统的并发模型,今天我们就说一下go中的锁的使用。

go语言并发之锁的基操

互斥锁是传统并发对共享的资源进行访问空值的主要手段,在 sync 包中,Mutex 结构体表示。该结构体具备两个公共的方法,Lock和Unlock,前者锁定当前的互斥量,后者是解锁。这两个一定要一起使用,由于defer的存在,我们基本上是不会忘记解锁的,代码示例:

import "sync"
func main(){
 var m sync.Mutex
 
 m.Lock()
 defer m.Unlock()
 // do something
}

互斥锁只能锁定一次,当在解锁之前再次进行加锁,便会死锁状态,如果在加锁前解锁,便会报错“panic: sync: unlock of unlocked mutex”

还有另外一个锁就是读写锁,顾名思义就是对读写操作的锁,与互斥锁的不同处主要是可以分别针对读写操作进行锁定和解锁。读写锁控制下,多个写操作是互斥的,读与写操作也是互斥的,但是多个读操作之间是不存在互斥的。在 sync 包中,RWMutex 结构体表示。

读写锁具有下面四个方法:

var m sync.RWMutex

m.Lock()
m.Unlock()
m.RLock()
m.RUnlock()

Lock和Unlock是对写操作的锁,RLock和RUnlock是对读操作的锁。

读写锁的写锁只能锁定一次,解锁前不能多次锁定,读锁可以多次,但读解锁次数最多只能比读锁次数多一次,一般情况下不建议读解锁次数多余读锁次数

在写代码时,如果map遇到了并发的写入数据,程序会panic的,所以对map的操作我们要考虑到并发,我们可以在map写入数据时对其加锁。

ma := make(map[string]string)

m.Lock()
ma["key"] = "value
m.Unlock()

当然go语言给我们提供了一种同步的map,sync.Map,这个我们不需要加锁,只需要调用其已有的方法即可,具体内容不在这里实现,感兴趣的可以看一下同步map的使用。

还有一个就是sync包中的Once,在我之前的单例模式的文章中说过,这个是只会执行一次,所以我们基本上都是在这里面做只需要一次的初始化的操作,当然这个也是go语言实现单例模式(对设计模式感兴趣的同学可以看我之前的文章)的不二选择。

var ma map[string]string
var once sync.Once
once.Do(func() {
 ma = make(map[string]string)
})

后续会有更多的模式和算法以及区块链相关的,如果你是想学习go语言或者是对设计模式或者算法感兴趣亦或是区块链开发工作者,都可以关注一下。(微信公众号:Go语言之美,更多go语言知识信息等)。公众号会持续为大家分享更多干货。

相关推荐