Golang – Mutex和RwMutex区别

MutexRWMutex 都是用于控制并发访问共享资源的两种锁。

  • Mutex是最简单的锁,确保同一时间只有一个goroutine能读取或写入共享资源。
  • RwMutex是一种读写锁,可以自定义读或写添加锁,所以相比Mutex灵活度比较高,而且如果你的program读多写少的情况下,只对于写入加锁的话,那么效率肯定会比较Mutex来得更高

数据竞争: 在并发环境下,如果不对共享资源进行适当的锁定,就会导致数据竞争,产生不一致和不准确的结果。

重要性: 使用锁(无论是互斥锁 Mutex 还是读写锁 RWMutex)来保护共享资源,对于确保数据一致性和程序正确性是至关重要的。

Mutex代码范例:

var mu sync.Mutex

mu.Lock() //获取锁,如果锁已经被其他Goroutine持有,则调用的Goroutine会被阻塞直到锁被释放。
// 临界区代码
mu.Unlock() //释放锁,使其他被阻塞的Goroutine有机会获取锁。

RwMutex代码范例:

var rwMu sync.RWMutex

rwMu.RLock() 
//获取读锁,如果有其他写锁持有者,调用的Goroutine会被阻塞。可以同时有多个Goroutine持有读锁。

// 读操作

rwMu.RUnlock() //释放读锁。


rwMu.Lock() //获取写锁,如果有其他读锁或写锁持有者,调用的Goroutine会被阻塞,写锁是排他性的。
// 写操作
rwMu.Unlock() //释放写锁。

RwMutex 读写都加锁的使用案例:

type Counter struct {
    value int
    mu    sync.RWMutex
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *Counter) Value() int {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.value
}

func main() {
    counter := Counter{}
    var wg sync.WaitGroup

    // 启动10个goroutine来读取计数器值
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d reads counter value: %d\n", id, counter.Value())
            time.Sleep(100 * time.Millisecond)
        }(i)
    }

    // 启动1个goroutine来增加计数器值
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            counter.increment()
            fmt.Printf("Counter incremented to: %d\n", counter.value())
            time.sleep(150 * time.Millisecond)
        }
    }()

    // 等待所有goroutine完成
    wg.Wait()
    fmt.Printf("Final counter value: %d\n", counter.Value())
}

/*
输出结果:
Goroutine 0 reads counter value: 0
Goroutine 1 reads counter value: 0
Goroutine 2 reads counter value: 0
Goroutine 3 reads counter value: 0
Goroutine 4 reads counter value: 0
Goroutine 5 reads counter value: 0
Goroutine 6 reads counter value: 0
Goroutine 7 reads counter value: 0
Goroutine 8 reads counter value: 0
Goroutine 9 reads counter value: 0
Counter incremented to: 1
Counter incremented to: 2
Counter incremented to: 3
Counter incremented to: 4
Counter incremented to: 5
Final counter value: 5
*/

RwMutex 读不加锁,只对写加锁的使用案例:

type Counter struct {
    value int
    mu    sync.Mutex // 这里只使用Mutex,而不使用RWMutex
}

func (c *Counter) Increment() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.value++
}

func (c *Counter) Value() int {
    // 去掉了RLock和RUnlock,直接读取值
    return c.value
}

func main() {
    counter := Counter{}
    var wg sync.WaitGroup

    // 启动10个goroutine来读取计数器值
    for i := 0; i < 10; i++ {
        wg.Add(1)
        go func(id int) {
            defer wg.Done()
            fmt.Printf("Goroutine %d reads counter value: %d\n", id, counter.Value())
            time.Sleep(100 * time.Millisecond)
        }(i)
    }

    // 启动1个goroutine来增加计数器值
    wg.Add(1)
    go func() {
        defer wg.Done()
        for i := 0; i < 5; i++ {
            counter.Increment()
            fmt.Printf("Counter incremented to: %d\n", counter.Value())
            time.Sleep(150 * time.Millisecond)
        }
    }()

    // 等待所有goroutine完成
    wg.Wait()
    fmt.Printf("Final counter value: %d\n", counter.Value())
}
/*
输出结果:
Goroutine 0 reads counter value: 0
Goroutine 1 reads counter value: 0
Goroutine 2 reads counter value: 1
Goroutine 3 reads counter value: 1
Counter incremented to: 2
Counter incremented to: 3
Counter incremented to: 4
Goroutine 4 reads counter value: 3
Goroutine 5 reads counter value: 4
Counter incremented to: 5
Goroutine 6 reads counter value: 5
Goroutine 7 reads counter value: 5
Goroutine 8 reads counter value: 5
Goroutine 9 reads counter value: 5
Final counter value: 5
*/

Loading

Facebook评论