GO中sync 包的 RWMutex 读写互斥锁
文章目录
- 背景
- RWMutex 简介
- 代码验证
- 多个协程请求读锁 `RLock()` 和 `RLock()`
- 读写交错 `RLock()` 和 `Lock()`
- 写入的时候读取
- 读取的时候写入
- 请求多个写`Lock()` 和 `Lock()`
背景
Mutex 互斥锁是严格锁定读和写,如果我们需要单独对读或者写添加锁需要使用 sync包的RWMutex
针对读多写少的情况:
读写锁的原则是
1、可以随便读,多个协程同时读。
2、写的时候,不能读也不能写。
RWMutex 简介
RWMutex 类型一共有 6 个方法,
RLock/RUnlock:RLock 锁定读操作,如果锁已被写操作持有,RLock 方法会被阻塞,直到锁释放;如果锁已被读操作持有,则无限制,可以读取内容。RUnlock 是读操作对应的释放锁的方法。
Lock/Unlock:Lock 锁定读写操作,不管是读操作持有锁,还是写操作持有锁,Lock 方法都会被阻塞,直到锁释放。Unlock 是对应的释放锁方法。一般用于写操作的场景。
rUnlockSlow:检查读操作是否全部释放锁,如果读锁全部释放,才可以唤醒写操作去请求写锁。
RLocker:RLocker 为读操作返回一个 Locker 接口,它的 Lock 方法会调用 RWMutex 类型的 RLock方法,它的 Unlock 方法会调用 RWMutex 类型的 RUnlock方法。
其中 RLock() 和 RLock() 之间并不互斥,可以共享锁,Lock() 和 Lock() 之间还有 RLock() 和 Lock() 之间是互斥的.
代码验证
多个协程请求读锁 RLock() 和 RLock()
package mainimport ("fmt""time""sync"
)// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {mu = new(sync.RWMutex)for i:= 0; i< 1000; i++ {go readLock(i)}time.Sleep(2*time.Second)
}func readLock(i int) {mu.RLock()count++fmt.Println(i," Read Lock is", count)mu.RUnlock()
}

如上代码所示, 我们启动1000个协程,每个协程执行的readLock 中都添加了 RLock(). 执行结果如下:
结果发现,count 数字打印杂乱无章,说明这些协程同时持有锁,多个RLock() 之间并不互斥。
读写交错 RLock() 和 Lock()
写入的时候读取
package mainimport ("fmt""time""sync"
)// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {mu = new(sync.RWMutex)for i := 0; i< 5; i++ {go readLock(1)}for i := 0; i< 5; i++ {go writLock(1)}time.Sleep(30*time.Second)
}func writLock(i int){mu.Lock()fmt.Println(i," Writ Lock start", count)count++fmt.Println(i," Writ Lock is", count)time.Sleep(1 *time.Second)fmt.Println(i," Writ Lock done", count)mu.Unlock()
}func readLock(i int) {mu.RLock()fmt.Println(i," Read Lock is", count)// time.Sleep(10 *time.Second)fmt.Println(i," Read Lock done")mu.RUnlock()
}
Lock() 写入的时候,sleep 期间, 使用 RLock() 读取, 结果如下

发现在 write 等待的时候 read 并没有获得锁, 说明 Lock() 锁未释放, RLock() 不能获得锁
读取的时候写入
package mainimport ("fmt""time""sync"
)// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {mu = new(sync.RWMutex)for i := 0; i< 10; i++ {go readLock(1)}for i := 0; i< 10; i++ {go writLock(1)}time.Sleep(15*time.Second)
}func writLock(i int){mu.Lock()fmt.Println(i," Writ Lock start", count)count++fmt.Println(i," Writ Lock is", count)// time.Sleep(1 *time.Second)fmt.Println(i," Writ Lock done", count)mu.Unlock()
}func readLock(i int) {mu.RLock()fmt.Println(i," Read Lock is", count)time.Sleep(10 *time.Second)fmt.Println(i," Read Lock done")mu.RUnlock()
}
在 RLock() sleep 期间, 使用 Lock() 结果如下

read 期间, writ 并没有获得锁。 证明了 RLock() 和 Lock() 是互斥的。
请求多个写Lock() 和 Lock()
package mainimport ("fmt""time""sync"
)// 声明Mutex变量
var mu *sync.RWMutex
var count = 0
func main() {mu = new(sync.RWMutex)for i:= 0; i< 1000; i++ {go writLock(i)}time.Sleep(2*time.Second)
}func writLock(i int){mu.Lock()count++fmt.Println(i," Writ Lock is", count)mu.Unlock()
}
启动1000个线程, 使用 Lock() 执行 count ++, 结果如下

发现最红结果是1000,并且是按照顺序进行计算的。 说明多个协程之间的Lock() 是互斥的。
相关文章:
GO中sync 包的 RWMutex 读写互斥锁
文章目录背景RWMutex 简介代码验证多个协程请求读锁 RLock() 和 RLock()读写交错 RLock() 和 Lock()写入的时候读取读取的时候写入请求多个写Lock() 和 Lock()背景 Mutex 互斥锁是严格锁定读和写,如果我们需要单独对读或者写添加锁需要使用 sync包的RWMutex 针对读…...
糖化学试剂55520-67-7,5-vinyl-2-deoxyuridine,5-乙烯基-2-脱氧尿苷特点分析说明
5-vinyl-2-deoxyuridine(5-VdU),5-vinyl-2-deoxyuridine,5-Vinyldeoxyuridine5-乙烯基-2-脱氧尿苷 | CAS:55520-67-7 | 纯度:95%试剂信息:CAS:55520-67-7所属类别:糖化学分子量:C11H…...
五年携手共话,FISCO BCOS为数实相生注入新动能
2月24日,作为深圳国际金融科技节系列活动之一,由深圳市地方金融监督管理局指导,微众银行、金链盟主办的“2022产业区块链年度峰会暨FISCO BCOS五周年生态大会”(下称“大会”)在深圳顺利召开。本次大会以“数实相生&am…...
特征可视化技术t-SNE
特征可视化技术t-SNE 一、理论介绍 想要了解t-SNE的数学原理可以参考t-SNE完整笔记 关于t-SNE的使用过程中有以下几点需要注意: t-SNE算法并不是每次都能产生相似结果。 t-SNE算法使得距离的概念适应于数据集中的区域密度变化。因此,它自然而然地扩大…...
.NET 导入导出Project(mpp)以及发布后遇到的Com组件问题
最近公司项目有一个对Project导入导出的操作,现在市面上能同时对Project进行导入导出的除了微软自带的Microsoft.Office.Interop.MSProject,还有就是Aspose.Tasks for .NET。但因为后者是收费软件且破解版的现阶段只到18.11,只支持.net Frame…...
centos 8安装配置 yum/dnf镜像源 以及 docker相关操作
Docker简介 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的Linux或Windows操作系统的机器上,也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。 Docker组成部分: 镜…...
java基础之线程池
线程池1.线程池1.1 线程状态介绍1.2 线程池-基本原理1.3 线程池-Executors默认线程池1.4 线程池-Executors创建指定上限的线程池1.5 线程池-ThreadPoolExecutor1.6 线程池-参数详解1.7 线程池-非默认任务拒绝策略2. 原子性2.1 volatile-问题2.2 volatile解决2.3 synchronized解…...
Substrate 基础 -- 教程(Tutorials)
官网 github DOC 面向未来的区块链框架 Substrate 使开发人员能够快速、轻松地构建适合任何用例的未来 证明区块链(future proof blockchains)。 Substrate 文档包括区块链构建器(blockchain builders)和parachain 项目团队的概念、过程和参考信息。…...
一个线程两次调用start()方法会出现什么情况?
第17讲 | 一个线程两次调用start()方法会出现什么情况? 今天我们来深入聊聊线程,相信大家对于线程这个概念都不陌生,它是 Java 并发的基础元素,理解、操纵、诊断线程是 Java 工程师的必修课,但是你真的掌握线程了吗&am…...
看完再拿五分,软考高项时政提分必备
时事政治题作为软考信息系统项目管理师当中的必考题,每年都让不少考生头疼,主要吧,它一不在教材里,二考的又很随意,如果不是平时积累,专门注意去看,有时候很难答得对,弄得这几分就完…...
界面开发(1) --- PyQt5环境配置
PyQt5环境配置 第一步:首先安装社区版Pycharm 下载地址:https://www.jetbrains.com/pycharm/download/#sectionwindows 第二步:安装Anaconda3,配置虚拟环境 下载地址:https://www.anaconda.com/ 第三步࿱…...
shield分析
本文仅供学习交流,只提供关键思路不会给出完整代码,严禁用于非法用途,若有侵权请联系我删除!技术交流合作请私信! 熟练打开Fiddler设置好手机代理,摆弄半天一直抓不到包,应该是小红书监测到了F…...
Javaweb增删改查之【查】
Javaweb增删改查之【查】1.前端页面2.java链接数据库——集成mybatis2.1 建立层2.2 实体层entity2.3 mapper(dao层)2.4 mybatis配置文件2.5工具层util3.后台功能3.1servlet前几天跟着b站up主学javaweb登录,突然还是觉得这几年学了c是真的挺好…...
C++ STL:迭代器 Iterator
文章目录1、迭代器的类型2、traitsiterator_traitstype_traits泛化的指针,容器与算法的桥梁。提供一种方法,按照一定顺序访问一个聚合对象中各个元素,而又不暴露该对象的内部表示。既能对容器进行遍历,又可以对外隐藏容器的底层实…...
【C++】泛型编程——模板初阶
文章目录1. 泛型编程2. 函数模板2.1 函数模板的概念2.2 函数模板的使用2.3 函数模板的原理2.4 函数模板的实例化隐式实例化显式实例化2.5 模板参数的匹配原则3. 类模板1. 泛型编程 首先我们来思考一个问题:如何实现一个通用的交换函数呢? 即我们想交换两…...
数据结构入门--时间 空间复杂度
数据结构入门 时间 空间复杂度解析 目录 一. 算法效率 二. 时间复杂度 2.1 时间复杂度的概念 2.2 大O的渐进表示法 2.3 题目练习 题目一 题目二 题目三 题目四 题目五 题目六 题目七 三. 空间复杂度 3.1 题目练习 题目一 题目二 题目三 一. 算法效率 算法效率…...
计算机操作系统第一章
操作系统引论1.1操作系统的目标和作用定义:操作系统是控制管理计算机系统的硬软件,分配调度资源的系统软件。目标:方便性,有效性(提高系统资源的利用率、提高系统的吞吐量),可扩充性,…...
ARM LDREX/STREX指令以及独占监控器详解
一、目的Linux驱动开发中有一个特别重要的知识点必须掌握,即并发、竞态以及同步。什么是并发?多个执行单元(进程、线程、中断)同时对一个共享资源的进行访问;此处的共享资源可以是外设、内存或者软件层面的全局变量静态…...
吉林大学 程序设计基础 2022级 实验复盘 2.23
本人能力有限,发出只为帮助有需要的人。 以下为实验课的复盘,内容会有大量失真,请多多包涵。 此次实验限时一个小时,时间很紧张,很多内容可能并不准确。 1.输出有规律的字母串 输入输出如下; 输入&…...
Linux系列 常用命令(目录和文件管理)vi和vim 编辑使用,(笔记)
作者简介:一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页 目录 前言 一.常用命令(目录和文件管理) 1.查看文件内容 2.统计…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
实现弹窗随键盘上移居中
实现弹窗随键盘上移的核心思路 在Android中,可以通过监听键盘的显示和隐藏事件,动态调整弹窗的位置。关键点在于获取键盘高度,并计算剩余屏幕空间以重新定位弹窗。 // 在Activity或Fragment中设置键盘监听 val rootView findViewById<V…...
Selenium常用函数介绍
目录 一,元素定位 1.1 cssSeector 1.2 xpath 二,操作测试对象 三,窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四,弹窗 五,等待 六,导航 七,文件上传 …...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅!
【把数组变成一棵树】有序数组秒变平衡BST,原来可以这么优雅! 🌱 前言:一棵树的浪漫,从数组开始说起 程序员的世界里,数组是最常见的基本结构之一,几乎每种语言、每种算法都少不了它。可你有没有想过,一组看似“线性排列”的有序数组,竟然可以**“长”成一棵平衡的二…...
