您现在的位置是:首页 >技术教程 >Golang中的互斥锁Mutex与读写锁RWMutex详解网站首页技术教程

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

路多辛 2024-06-17 10:19:58
简介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次并发读操作。在并发读的时候,使用读锁来支持并发访问。

小结

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

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。