Golang学习笔记之互斥锁(Mutex)

摘要:Go语言包中的sync包提供了两种锁,互斥锁(sync.Mutex)和读写锁(sync.RWMutex)这一篇博文我们只说一下互斥锁。Mutex是一个互斥锁,可以创立为其余结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。? 它只有两个公开方法:Lock()加锁
Go语言包中的sync包提供了两种锁,互斥锁(sync.Mutex)和读写锁(sync.RWMutex)
这一篇博文我们只说一下互斥锁。

Mutex是一个互斥锁,可以创立为其余结构体的字段;零值为解锁状态。Mutex类型的锁和线程无关,可以由不同的线程加锁和解锁。

? 它只有两个公开方法:Lock()加锁,unlock()解锁。
? 在同一个协程中加锁后,不能再继续对其加锁,否则会panic。只有在解锁之后才能再次加锁。
? 只允许只有一个读或者者写的场景
? 在使用Unlock()解锁前,未使用Lock()加锁,就会引起一个运行错误。

函数原型
func (m *Mutex) Lock()
Lock方法锁住m,假如m已经加锁,则阻塞直到m解锁。
func (m *Mutex) Unlock()
Unlock方法解锁m,假如m未加锁会导致运行时错误。锁和线程无关,可以由不同的线程加锁和解锁。
一个例子了解互斥锁的作用

package mainimport (    "fmt"    "sync")var num = 0func increment(wg *sync.WaitGroup) {    num = num + 1    wg.Done()}func main() {    var w sync.WaitGroup    for i := 0; i < 1000; i++ {        w.Add(1)        //开启协程        go increment(&w)    }    w.Wait()    fmt.Println("num =", num)}

在上述程序中,调用1000个协程来进行num=num+1操作
运行几次的输出分别为
num = 971
num = 944
num = 959
每次运行都没有达到预期的效果,由于多个并发的协程试图访问 num 的值,这时就会发生竞态条件。
现在我们可以对上述程序加上锁,每次只能由一个线程来操作num的值

package mainimport (    "fmt"    "sync")var num = 0func increment(wg *sync.WaitGroup, m *sync.Mutex) {    //互斥锁    m.Lock()     //当有线程进去进行加锁    num = num + 1    m.Unlock()   //出来后解锁,其余线程才可以进去    wg.Done()}var w sync.WaitGroup    var m sync.Mutex    for i := 0; i < 1000; i++ {        w.Add(1)        go increment(&w, &m)//这里要传引用并不能传值,假如传值,那么每个协程都会得到 Mutex 的一份拷贝,竞态条件还是会发生。    }    w.Wait()    fmt.Println("num =", num)

输出
num = 1000
我们也可以使用缓冲信道来实现互斥锁

func increment2(wg *sync.WaitGroup, b chan bool) {    //自己设置互斥锁    b <- true    num = num + 1    <-b    wg.Done()}func main() {    var w sync.WaitGroup    ch := make(chan bool,1)    for i := 0; i < 1000; i++ {        w.Add(1)        go increment2(&w, ch)    }    w.Wait()    fmt.Println("num =", num)}

输出
num = 1000

func main() {    wa := sync.WaitGroup{}    var mu sync.Mutex    fmt.Println("加锁0")    mu.Lock()    fmt.Printf("上锁中0\t")    for i := 1; i < 4; i++ {        wa.Add(1)        go func(i int) {            fmt.Printf("加锁%d\t", i)            mu.Lock()            fmt.Printf("上锁中%d\t", i)            time.Sleep(time.Second * 1)            mu.Unlock()            fmt.Printf("解锁%d\t", i)            wa.Done()        }(i)    }    time.Sleep(time.Second * 5)    mu.Unlock()    fmt.Println("\n解锁0")    wa.Wait()}

输出为
加锁0
上锁中0 加锁2 加锁3 加锁1 上锁中2
解锁0
解锁2 上锁中3 解锁3 上锁中1 解锁1

  • 全部评论(0)
最新发布的资讯信息
【系统环境|】Fortigate飞塔防火墙如何开启DNS转发/DNS代理(2025-10-14 23:58)
【系统环境|】有了它,再也不用担心电脑弹窗广告和病毒啦!(2025-10-14 23:57)
【系统环境|】如何关闭恼人的电脑弹窗广告?2招搞定(2025-10-14 23:55)
【系统环境|】实用软件推荐:电脑广告弹窗多?用他,都给你屏蔽掉!(2025-10-14 23:55)
【系统环境|】Nginx篇01——基本安装配置和静态页面设置(2025-10-14 23:54)
【系统环境|】Linux端口开放,查看,删除,防火墙(2025-10-14 23:53)
【系统环境|】安全HTTP头部配置: 基于CSP与HSTS的Web安全策略(2025-10-14 23:52)
【系统环境|】老K:做私域过1000万的赛道全部都聚焦在女性身上!(2025-10-14 23:51)
【系统环境|】JavaScript跨域问题: 如何解决跨域访问和资源共享的安全策略(2025-10-14 23:51)
【系统环境|】家庭七级财务防火墙(2025-10-14 23:50)
手机二维码手机访问领取大礼包
返回顶部