Golang 中 sync 包实现了两种锁,Mutex(互斥锁)和 RWMutex(读写锁),其中 RWMutex 是基于 Mutex 实现的。


1.sync.Mutex

type Mutex struct {

// contains filtered or unexported fields

}


func (m *Mutex) Lock()

func (m *Mutex) Unlock()


sync.Mutex 用于多个 goroutine 对共享资源的互斥访问。使用要点如下:

(1)使用 Lock() 加锁,Unlock() 解锁;

(2)对未解锁的 Mutex 使用 Lock() 会阻塞;

(3)对未上锁的 Mutex 使用 Unlock() 会导致 panic 异常。


多个 goroutine 对同一个全局变量读写需要加锁,示例如下:


package main


import (

    "fmt"

    "sync"

)


func main() {

        var intVar int

        var wg sync.WaitGroup

        var mutex sync.RWMutex

    go func(){

        defer wg.Done()

        mutex.Lock()

        intVar=4

        mutex.Unlock()

        fmt.Printf("first goroutine, intVar=%d\n",intVar)

        }()


    go func(){

        defer wg.Done()

        mutex.Lock()

        intVar=5

        mutex.Unlock()

        fmt.Printf("second goroutine, intVar=%d\n",intVar)

    }()


    wg.Add(2)

    wg.Wait()

    fmt.Println("end main goroutine")

}


输出结果:


second goroutine, intVar=5

first goroutine, intVar=4

end main goroutine


//或

first goroutine, intVar=4

second goroutine, intVar=5

end main goroutine


在解锁之前加锁会导致死锁。


package main


import (

    "fmt"

    "sync"

)


func main(){

    var mutex sync.Mutex

    mutex.Lock()

    fmt.Println("Locked")

    mutex.Lock()

}


输出结果:


Locked

fatal error: all goroutines are asleep - deadlock!


2.sync.RWMutex

type RWMutex struct {

// contains filtered or unexported fields

}


func (rw *RWMutex) Lock()

func (rw *RWMutex) RLock()

func (rw *RWMutex) RLocker() Locker

func (rw *RWMutex) RUnlock()

func (rw *RWMutex) Unlock()


sync.RWMutex 用于读锁和写锁分开的情况。使用时注意如下几点:

(1)RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁;

(2)读锁占用的情况下会阻止写,不会阻止读,多个 goroutine 可以同时获取读锁;

(3)写锁会阻止其他 goroutine(无论读和写)进来,整个锁由该 goroutine 独占;

(4)适用于读多写少的场景。


2.1 Lock()与Unlock()

(1)Lock() 加写锁,Unlock() 解写锁

(2)如果在加写锁之前已经有其他的读锁和写锁,则 Lock() 会阻塞直到该锁可用,为确保该锁可用,已经阻塞的 Lock() 调用会从获得的锁中排除新的读取器,即写锁权限高于读锁,有写锁时优先进行写锁定;

(3)在 Lock() 之前使用 Unlock() 会导致 panic 异常。


2.2 RLock() 和 RUnlock()

(1)RLock() 加读锁,RUnlock() 解读锁;

(2)RLock() 加读锁时,如果存在写锁,则无法加读锁;当只有读锁或者没有锁时,可以加读锁,读锁可以加多个;

(3)RUnlock() 解读锁,RUnlock() 撤销单次 RLock() 调用,对于其他同时存在的读锁则没有效果;

(4)在没有读锁的情况下调用 RUnlock(),会导致 panic 错误;

(5)RUnlock() 的个数不得多于 RLock(),否则会导致 panic 错误。


Go map 的读写是非原子操作,如果有多个 goroutine 同时对 map 进行操作时,需要加读写锁。


package main


import (

    "sync"

    "fmt"

)


func main() {

    mapNameAge :=make(map[string]int)

    var rwMutex sync.RWMutex

    var wg sync.WaitGroup

    go func(){

        defer wg.Done()

        rwMutex.Lock()

        mapNameAge["dablelv"]=18

        rwMutex.Unlock()

        fmt.Println("first goroutine to write map end")

    }()


    go func(){

        defer wg.Done()

        rwMutex.RLock()

        age, _ :=mapNameAge["dablelv"]

        rwMutex.RUnlock()

        fmt.Printf("second goroutine to read map end, map[dablelv]=%d\n",age)

    }()


    wg.Add(2)

    wg.Wait()

    fmt.Println("main goroutine end")

}


输出结果:


second goroutine to read map end, map[dablelv]=0

first goroutine to write map end

main goroutine end


//或

first goroutine to write map end

second goroutine to read map end, map[dablelv]=18

main goroutine end


2.3 错误使用异常

(1)Unlock() 使用之前不存在 Lock()。


package main


import (

    "sync"

)


func main(){

    var rwMutex sync.RWMutex

    rwMutex.Unlock()

}


程序输出:


panic: sync: Unlock of unlocked RWMutex


(2)RUnlock() 之前不存在 RLock()。


package main


import (

    "sync"

)


func main(){

    var rwMutex sync.RWMutex

    rwMutex.RUnlock()

}


程序输出:


fatal error: sync: RUnlock of unlocked RWMutex


(3)RWMutex 使用不当导致的死锁。


package main


import (

    "sync"

)


func main(){

    var rwmutex *sync.RWMutex

    rwmutex = new(sync.RWMutex)

    rwmutex.Lock()

    rwmutex.Lock()

}


程序输出:


fatal error: all goroutines are asleep - deadlock!


(4)RUnlock() 个数多于 RLock()。


package main


import (

    "sync"

)


func main(){

    var rwmutex *sync.RWMutex

    rwmutex = new(sync.RWMutex)

    rwmutex.RLock()

    rwmutex.RLock()

    rwmutex.RUnlock()

    rwmutex.RUnlock()

    rwmutex.RUnlock()

}

程序输出:


panic: sync: RUnlock of unlocked RWMutex


点赞(365)

评论列表共有 0 条评论

立即
投稿
返回
顶部