大连免费网站制作,织梦网站主页文章列表调用,wordpress后台添加图片,网页设计规划书样本在并发编程中#xff0c;锁是一种常用的同步机制#xff0c;用来保护共享资源的安全访问和修改。Golang 作为一门支持并发的语言#xff0c;提供了两种主要的锁类型#xff1a;互斥锁#xff08;Mutex#xff09;和读写锁#xff08;RWMutex#xff09;。本文将介绍这两…在并发编程中锁是一种常用的同步机制用来保护共享资源的安全访问和修改。Golang 作为一门支持并发的语言提供了两种主要的锁类型互斥锁Mutex和读写锁RWMutex。本文将介绍这两种锁的概念、用法和注意事项。
互斥锁
互斥锁是最简单也最常见的一种锁它用来实现对共享资源的排他访问即同一时刻只能有一个 goroutine 获得该锁其他 goroutine 只能等待直到该锁被释放。Golang 中的互斥锁由 sync.Mutex 结构体表示它有两个方法Lock() 和 Unlock()。Lock() 方法用来加锁Unlock() 方法用来解锁。使用互斥锁的一般模式如下
var mu sync.Mutex // 创建一个互斥锁
mu.Lock() // 加锁
// do something with shared resource
mu.Unlock() // 解锁互斥锁的使用需要注意以下几点
不要重复加锁或解锁否则会导致运行时错误或死锁。不要忘记解锁否则会导致其他 goroutine 阻塞可以使用 defer 语句来确保解锁。不要在多个函数之间传递互斥锁否则会增加复杂度和出错的风险建议将互斥锁和共享资源封装在同一个结构体中提供加锁和解锁的方法。
互斥锁适用于读写不确定或者写多读少的场景例如对一个计数器的增加操作就需要用互斥锁来保证原子性和一致性。下面是一个使用互斥锁的例子
package mainimport (fmtsync
)var (count intmu sync.Mutex
)func main() {for i : 0; i 10; i {go func() {for j : 0; j 10000; j {mu.Lock() // 加锁count // 修改共享资源mu.Unlock() // 解锁}}()}// 等待所有 goroutine 结束var wg sync.WaitGroupwg.Add(1)go func() {for {mu.Lock() // 加锁c : count // 读取共享资源mu.Unlock() // 解锁if c 100000 {break}}wg.Done()}()wg.Wait()fmt.Println(count) // 输出 100000
}读写锁
读写锁是一种更复杂的锁它用来实现对共享资源的读写分离即允许多个 goroutine 同时读取资源但只允许一个 goroutine 写入资源从而提高了并发性能。Golang 中的读写锁由 sync.RWMutex 结构体表示它有四个方法RLock()RUnlock()Lock() 和 Unlock()。RLock() 和 RUnlock() 用来加解读锁Lock() 和 Unlock() 用来加解写锁。使用读写锁的一般模式如下
var rw sync.RWMutex // 创建一个读写锁
rw.RLock() // 加读锁
// do something with shared resource for reading
rw.RUnlock() // 解读锁
rw.Lock() // 加写锁
// do something with shared resource for writing
rw.Unlock() // 解写锁读写锁的使用需要注意以下几点
不要同时加读锁和写锁否则会导致死锁。不要重复加锁或解锁否则会导致运行时错误或死锁。不要忘记解锁否则会导致其他 goroutine 阻塞可以使用 defer 语句来确保解锁。不要在多个函数之间传递读写锁否则会增加复杂度和出错的风险建议将读写锁和共享资源封装在同一个结构体中提供加锁和解锁的方法。
读写锁适用于读多写少的场景例如对一个缓存的查询操作就可以用读写锁来提高效率。下面是一个使用读写锁的例子
package mainimport (fmtmath/randsynctime
)var (cache make(map[int]int) // 缓存rw sync.RWMutex // 读写锁
)func main() {// 模拟多个 goroutine 同时读写缓存for i : 0; i 10; i {go func() {for {key : rand.Intn(5)rw.RLock() // 加读锁value : cache[key] // 从缓存中读取数据rw.RUnlock() // 解读锁fmt.Printf(goroutine %d read key %d value %d\n, i, key, value)time.Sleep(time.Millisecond * 10)}}()}for i : 0; i 2; i {go func() {for {key : rand.Intn(5)value : rand.Intn(100)rw.Lock() // 加写锁cache[key] value // 向缓存中写入数据rw.Unlock() // 解写锁fmt.Printf(goroutine %d write key %d value %d\n, i10, key, value)time.Sleep(time.Millisecond * 100)}}()}// 主 goroutine 等待select {}
}总结
本文介绍了 Golang 中的两种锁类型互斥锁和读写锁以及它们的概念、用法和注意事项。互斥锁用来实现对共享资源的排他访问适用于读写不确定或者写多读少的场景。读写锁用来实现对共享资源的读写分离适用于读多写少的场景。在使用锁的时候要注意避免重复加锁或解锁、忘记解锁、死锁等问题以及尽量减少锁的粒度和范围提高并发性能。