Golang中的互斥锁Mutex与读写锁RWMutex详解

Golang中的互斥锁Mutex与读写锁RWMutex详解

Golang中的sync包实现了两种锁:互斥锁(Mutex)和读写锁(RWMutex)。

互斥锁(sync.Mutex)

  • 使用Lock方法加锁,使用Unlock方法解锁,Golang从1.18新增了TryLock方法,用于尝试获取锁,返回成功或者失败;
  • 如果Mutex被一个goroutine获取后,其他goroutine只能等到这个goroutine释放该Mutex后才能获取;
  • 使用Lock方法加锁后,不能再次加锁,直到使用Unlock方法释放锁后才能再次加锁;加锁之前使用Unlock方法会导致panic;
  • Mutex并不与特定的goroutine相关联,一个goroutine加锁,也可以使用另一个goroutine解锁;
  • 在同一个goroutine中的Mutex解锁之前再次进行加锁,会导致死锁。

互斥锁的一个经典案例是对切片进行并发安全的操作,代码如下:

package main

import (
	"fmt"
	"sync"
)

var mu sync.Mutex
var slice []int

func main() {
	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func() {
			for j := 0; j < 100; j++ {
				mu.Lock()
				slice = append(slice, j)
				mu.Unlock()
			}
			wg.Done()
		}()
	}
	wg.Wait()
	fmt.Println(len(slice))
}

首先定义了一个长度为0的slice,并发地对其进行了1000次append操作。

读写锁(RWMutex)

  • RWMutex该锁可以加多个读锁(RLock)或者一个写锁(Lock),Golang从1.18新增了TryLock和TryRLock方法,分别用于尝试获取写锁和读锁,返回成功或者失败。
  • 读锁被占用的情况下会阻止写,不会阻止读,多个goroutine可以同时获得读锁。
  • 写锁会阻止其他goroutine对写锁和读锁的获取。

看一个代码示例:

package main

import (
	"log"
	"sync"
)

var mu sync.RWMutex
var m map[string]string

func main() {
	m = make(map[string]string)

	mu.Lock()
	m["a"] = "A"
	mu.Unlock()

	var wg sync.WaitGroup
	for i := 0; i < 10; i++ {
		wg.Add(1)
		go func(i int) {
			mu.RLock()
			log.Println(m["a"]) // 并发读
			mu.RUnlock()
			wg.Done()
		}(i)
	}
	wg.Wait()
}

首先定义了一个map,然后对其进行了一次写操作和10次并发读操作。在并发读的时候,使用读锁来支持并发访问。

小结

本文讲解了互斥锁和读写锁的特点,两种锁都可以用于协调多个并发访问共享资源的同步机制。可以看出互斥锁适用于读写不确定,并且只有一个读或者写的场景;读写锁适用于读多写少的场景,可以有更高的性能。需要注意的是尽量避免在锁的范围内进行耗时较长的操作,以免影响性能。

文章版权声明

 1 原创文章作者:2020.12.3.0:19、 ҉,如若转载,请注明出处: https://www.52hwl.com/30016.html

 2 温馨提示:软件侵权请联系469472785#qq.com(三天内删除相关链接)资源失效请留言反馈

 3 下载提示:如遇蓝奏云无法访问,请修改lanzous(把s修改成x)

 免责声明:本站为个人博客,所有软件信息均来自网络 修改版软件,加群广告提示为修改者自留,非本站信息,注意鉴别

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023年7月14日 上午12:00
下一篇 2023年7月15日