当前位置:首页 > 文章列表 > Golang > Go教程 > 怎么使用Go语言sync包与锁实现限制线程对变量的访问

怎么使用Go语言sync包与锁实现限制线程对变量的访问

来源:亿速云 2023-04-30 17:37:16 0浏览 收藏

“纵有疾风来,人生不言弃”,这句话送给正在学习Golang的朋友们,也希望在阅读本文《怎么使用Go语言sync包与锁实现限制线程对变量的访问》后,能够真的帮助到大家。我也会在后续的文章中,陆续更新Golang相关的技术文章,有好的建议欢迎大家在评论留言,非常感谢!

本篇内容主要讲解“怎么使用Go语言sync包与锁实现限制线程对变量的访问”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么使用Go语言sync包与锁实现限制线程对变量的访问”吧!

Go语言中 sync 包里提供了互斥锁 Mutex 和读写锁 RWMutex 用于处理并发过程中可能出现同时两个或多个协程(或线程)读或写同一个变量的情况。

为什么需要锁

锁是 sync 包中的核心,它主要有两个方法,分别是加锁(Lock)和解锁(Unlock)。

在并发的情况下,多个线程或协程同时其修改一个变量,使用锁能保证在某一时间内,只有一个协程或线程修改这一变量。

不使用锁时,在并发的情况下可能无法得到想要的结果,如下所示:

package main
import (
    "fmt"
    "time"
)
func main() {
    var a = 0
    for i := 0; i 

从理论上来说,上面的程序会将 a 的值依次递增输出,然而实际结果却是下面这样子的。

537
995
996
997
538
999
1000

通过运行结果可以看出 a 的值并不是按顺序递增输出的,这是为什么呢?

协程的执行顺序大致如下所示:

  • 从寄存器读取 a 的值;

  • 然后做加法运算;

  • 最后写到寄存器。

按照上面的顺序,假如有一个协程取得 a 的值为 3,然后执行加法运算,此时又有一个协程对 a 进行取值,得到的值同样是 3,最终两个协程的返回结果是相同的。

而锁的概念就是,当一个协程正在处理 a 时将 a 锁定,其它协程需要等待该协程处理完成并将 a 解锁后才能再进行操作,也就是说同时处理 a 的协程只能有一个,从而避免上面示例中的情况出现。 

互斥锁 Mutex

上面的示例中出现的问题怎么解决呢?加一个互斥锁 Mutex 就可以了。那什么是互斥锁呢 ?互斥锁中其有两个方法可以调用,如下所示:

func (m *Mutex) Lock()
func (m *Mutex) Unlock()

将上面的代码略作修改,如下所示:

package main
import (
    "fmt"
    "sync"
    "time"
)
func main() {
    var a = 0
    var lock sync.Mutex
    for i := 0; i 

运行结果如下:

goroutine 995, a=996
goroutine 996, a=997
goroutine 997, a=998
goroutine 998, a=999
goroutine 999, a=1000

需要注意的是一个互斥锁只能同时被一个 goroutine 锁定,其它 goroutine 将阻塞直到互斥锁被解锁(重新争抢对互斥锁的锁定),示例代码如下:

package main
import (
    "fmt"
    "sync"
    "time"
)
func main() {
    ch := make(chan struct{}, 2)
    var l sync.Mutex
    go func() {
        l.Lock()
        defer l.Unlock()
        fmt.Println("goroutine1: 我会锁定大概 2s")
        time.Sleep(time.Second * 2)
        fmt.Println("goroutine1: 我解锁了,你们去抢吧")
        ch 

上面的代码运行结果如下:

goroutine1: 我会锁定大概 2s
goroutine2: 等待解锁
goroutine1: 我解锁了,你们去抢吧
goroutine2: 欧耶,我也解锁了

读写锁

读写锁有如下四个方法:

  • 写操作的锁定和解锁分别是func (*RWMutex) Lock和func (*RWMutex) Unlock;

  • 读操作的锁定和解锁分别是func (*RWMutex) Rlock和func (*RWMutex) RUnlock。

读写锁的区别在于:

  • 当有一个 goroutine 获得写锁定,其它无论是读锁定还是写锁定都将阻塞直到写解锁;

  • 当有一个 goroutine 获得读锁定,其它读锁定仍然可以继续;

  • 当有一个或任意多个读锁定,写锁定将等待所有读锁定解锁之后才能够进行写锁定。

所以说这里的读锁定(RLock)目的其实是告诉写锁定,有很多协程或者进程正在读取数据,写操作需要等它们读(读解锁)完才能进行写(写锁定)。

我们可以将其总结为如下三条:

  • 同时只能有一个 goroutine 能够获得写锁定;

  • 同时可以有任意多个 gorouinte 获得读锁定;

  • 同时只能存在写锁定或读锁定(读和写互斥)。

示例代码如下所示:

package main

import (
    "fmt"
    "math/rand"
    "sync"
)
var count int
var rw sync.RWMutex
func main() {
    ch := make(chan struct{}, 10)
    for i := 0; i 

其执行结果如下:

goroutine 0 进入读操作...
goroutine 0 读取结束,值为:0
goroutine 3 进入读操作...
goroutine 1 进入读操作...
goroutine 3 读取结束,值为:0
goroutine 1 读取结束,值为:0
goroutine 4 进入写操作...
goroutine 4 写入结束,新值为:81
goroutine 4 进入读操作...
goroutine 4 读取结束,值为:81
goroutine 2 进入读操作...
goroutine 2 读取结束,值为:81
goroutine 0 进入写操作...
goroutine 0 写入结束,新值为:887
goroutine 1 进入写操作...
goroutine 1 写入结束,新值为:847
goroutine 2 进入写操作...
goroutine 2 写入结束,新值为:59
goroutine 3 进入写操作...
goroutine 3 写入结束,新值为:81

下面再来看两个示例。

【示例 1】多个读操作同时读取一个变量时,虽然加了锁,但是读操作是不受影响的。(读和写是互斥的,读和读不互斥)

package main
import (
    "sync"
    "time"
)
var m *sync.RWMutex
func main() {
    m = new(sync.RWMutex)
    // 多个同时读
    go read(1)
    go read(2)
    time.Sleep(2*time.Second)
}
func read(i int) {
    println(i,"read start")
    m.RLock()
    println(i,"reading")
    time.Sleep(1*time.Second)
    m.RUnlock()
    println(i,"read over")
}

运行结果如下:

1 read start
1 reading
2 read start
2 reading
1 read over
2 read over

【示例 2】由于读写互斥,所以写操作开始的时候,读操作必须要等写操作进行完才能继续,不然读操作只能继续等待。

package main
import (
    "sync"
    "time"
)
var m *sync.RWMutex
func main() {
    m = new(sync.RWMutex)
    // 写的时候啥也不能干
    go write(1)
    go read(2)
    go write(3)
    time.Sleep(2*time.Second)
}
func read(i int) {
    println(i,"read start")
    m.RLock()
    println(i,"reading")
    time.Sleep(1*time.Second)
    m.RUnlock()
    println(i,"read over")
}
func write(i int) {
    println(i,"write start")
    m.Lock()
    println(i,"writing")
    time.Sleep(1*time.Second)
    m.Unlock()
    println(i,"write over")
}

运行结果如下:

1 write start
3 write start
1 writing
2 read start
1 write over
2 reading

到此,相信大家对“怎么使用Go语言sync包与锁实现限制线程对变量的访问”有了更深的了解,不妨来实际操作一番吧!这里是golang学习网,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

理论要掌握,实操不能落!以上关于《怎么使用Go语言sync包与锁实现限制线程对变量的访问》的详细介绍,大家都掌握了吧!如果想要继续提升自己的能力,那么就来关注golang学习网公众号吧!

版本声明
本文转载于:亿速云 如有侵犯,请联系study_golang@163.com删除
如何修复 Windows 11 驱动程序不可用错误如何修复 Windows 11 驱动程序不可用错误
上一篇
如何修复 Windows 11 驱动程序不可用错误
真·重磅研究!32篇论文硬核盘点2022年度AI热点
下一篇
真·重磅研究!32篇论文硬核盘点2022年度AI热点
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ljg-skills -
    ljg-skills
    ljg-skills 是李继刚开源的 AI 技能与提示词集合,面向大模型使用者整理了一批可复用的 prompt、角色设定和任务技能模板,适合用于学习提示词设计、搭建个人 AI 工作流和沉淀团队常用智能体能力。
    2998次使用
  • MELO音乐 - AI 音乐生成平台,支持多模态创作能力
    MELO音乐
    MELO音乐是一站式AI视频与音乐制作助手,对标suno, udio的高品质体验。提供伴奏生成、原创写词、无损导出、哼唱识曲、混音变声等全套音频与短视频编辑工具。无论是流行Kpop、电音说唱、民谣古风、摇滚儿歌还是商用轻音乐,MELO为你免费谱曲,轻松做同款!
    2768次使用
  • UniScribe - AI 免费在线音视频转文字平台
    UniScribe
    UniScribe 是一款 AI 音视频转文字与内容整理工具,支持上传音频、视频文件或粘贴 YouTube 链接,自动生成转写文本、摘要、思维导图和关键问题,并支持多格式导出,适合会议记录、课程学习、访谈整理和内容创作复盘。
    2706次使用
  • 剧云 - 免费 AI 智能中文剧本创作平台
    剧云
    剧云是专业中文剧本创作平台,安全稳定运行十余年,集成AI编剧、剧本医生审核、人物小传、剧情关系图、大纲编写、多人协作、Word导入导出、版权管控功能,数据安全防护,轻松高效创作剧本。
    2935次使用
  • 万象有声 - AI 一站式有声内容创作平台
    万象有声
    万象有声,一个专为有声创作者打造的新一代智能有声内容创作平台。平台提供专业的智能拆章、智能画本编辑、AI配音、AI生成音效、后期制作、智能对轨、智能审听等有声创作全流程工具,可以帮助创作者高效、低成本创作出引人入胜的有声作品。立即体验,让有声书制作更简单!
    2882次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码