go中的sync.Mutex 和 sync.RWMutex

介绍

golang 中的 sync 包实现了两种锁:

  • Mutex:互斥锁
  • RWMutex:读写锁,RWMutex 基于 Mutex 实现

Mutex(互斥锁)

  • Mutex 为互斥锁,Lock() 加锁,Unlock() 解锁

  • 在一个 goroutine 获得 Mutex 后,其他 goroutine 只能等到这个 goroutine 释放该 Mutex

  • 使用 Lock() 加锁后,不能再继续对其加锁,直到利用 Unlock() 解锁后才能再加锁

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

  • 已经锁定的 Mutex 并不与特定的 goroutine 相关联,这样可以利用一个 goroutine 对其加锁,再利用其他 goroutine 对其解锁

  • 在同一个 goroutine 中的 Mutex 解锁之前再次进行加锁,会导致死锁

  • 适用于读写不确定,并且只有一个读或者写的场景

示例

加锁和解锁示例

package main

import (
   "fmt"
   "sync"
   "time"
)

func main() {
   var mutex sync.Mutex
   fmt.Println("Lock the lock")
   mutex.Lock()
   fmt.Println("The lock is locked")
   channels := make([]chan int, 4)
   for i := 0; i < 4; i++ {
      channels[i] = make(chan int)
      go func(i int, c chan int) {
         fmt.Println("Not lock: ", i)
         mutex.Lock()
         fmt.Println("Locked: ", i)
         time.Sleep(time.Second)
         fmt.Println("Unlock the lock: ", i)
         mutex.Unlock()
         c <- i
      }(i, channels[i])
   }
   time.Sleep(time.Second)
   fmt.Println("Unlock the lock")
   mutex.Unlock()
   time.Sleep(time.Second)

   for _, c := range channels {
      <-c
   }
}

程序输出:

Lock the lock
The lock is locked
Not lock:  0
Not lock:  3
Not lock:  1
Not lock:  2
Unlock the lock
Locked:  0
Unlock the lock:  0
Locked:  3
Unlock the lock:  3
Locked:  1
Unlock the lock:  1
Locked:  2
Unlock the lock:  2

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

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!

RWMutex(读写锁)

  • RWMutex 是单写多读锁,该锁可以加多个读锁或者一个写锁

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

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

  • 适用于读多写少的场景

Lock() 和 Unlock()

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

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

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

RLock() 和 RUnlock()

  • RLock() 加读锁,RUnlock() 解读锁

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

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

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

  • RUnlock() 的个数不得多余 RLock(),否则会导致 panic 错误

示例

Lock() 和 Unlock()

package main

import (
   "fmt"
   "sync"
   "time"
)

func main() {
   var mutex *sync.RWMutex
   mutex = new(sync.RWMutex)
   fmt.Println("Lock the lock")
   mutex.Lock()
   fmt.Println("The lock is locked")

   channels := make([]chan int, 4)
   for i := 0; i < 4; i++ {
      channels[i] = make(chan int)
      go func(i int, c chan int) {
         fmt.Println("Not lock: ", i)
         mutex.Lock()
         fmt.Println("Locked: ", i)
         fmt.Println("Unlock the lock: ", i)
         mutex.Unlock()
         c <- i
      }(i, channels[i])
   }
   time.Sleep(time.Second)
   fmt.Println("Unlock the lock")
   mutex.Unlock()
   time.Sleep(time.Second)

   for _, c := range channels {
      <-c
   }
}

程序输出:

Lock the lock
The lock is locked
Not lock:  0
Not lock:  3
Not lock:  1
Not lock:  2
Unlock the lock
Locked:  0
Unlock the lock:  0
Locked:  3
Unlock the lock:  3
Locked:  1
Unlock the lock:  1
Locked:  2
Unlock the lock:  2

Lock() 和 RLock()

package main

import (
   "fmt"
   "sync"
   "time"
)

func main() {
   var mutex *sync.RWMutex
   mutex = new(sync.RWMutex)
   fmt.Println("Lock the lock")
   mutex.Lock()
   fmt.Println("The lock is locked")

   channels := make([]chan int, 4)
   for i := 0; i < 4; i++ {
      channels[i] = make(chan int)
      go func(i int, c chan int) {
         fmt.Println("Not read lock: ", i)
         mutex.RLock()
         fmt.Println("Read Locked: ", i)

         time.Sleep(time.Second)
         fmt.Println("Unlock the read lock: ", i)
         mutex.RUnlock()
         c <- i
      }(i, channels[i])
   }
   time.Sleep(time.Second)
   fmt.Println("Unlock the lock")
   mutex.Unlock()
   time.Sleep(time.Second)

   for _, c := range channels {
      <-c
   }
}

程序输出:

Lock the lock
The lock is locked
Not read lock:  0
Not read lock:  3
Not read lock:  1
Not read lock:  2
Unlock the lock
Read Locked:  2
Read Locked:  0
Read Locked:  3
Read Locked:  1
Unlock the read lock:  1
Unlock the read lock:  3
Unlock the read lock:  2
Unlock the read lock:  0

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

package main

import (
   "sync"
)

func main() {
   var rwmutex *sync.RWMutex
   rwmutex = new(sync.RWMutex)
   rwmutex.Unlock()
}

程序输出:

fatal error: sync: Unlock of unlocked RWMutex

RWMutex 使用不当导致的死锁
示例1:

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!

示例2:

package main

import (
   "sync"
)

func main() {
   var rwmutex *sync.RWMutex
   rwmutex = new(sync.RWMutex)
   rwmutex.Lock()
   rwmutex.RLock()
}

程序输出:

fatal error: all goroutines are asleep - deadlock!

RUnlock() 之前不存在 RLock()

package main

import (
   "sync"
)

func main() {
   var rwmutex *sync.RWMutex
   rwmutex = new(sync.RWMutex)
   rwmutex.RUnlock()
}

程序输出:

fatal error: sync: RUnlock of unlocked RWMutex

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()
}

程序输出:

fatal error: sync: RUnlock of unlocked RWMutex

转自:https://andblog.cn/?p=2815

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值