golang中的锁分为互斥锁、读写锁、原子锁即原子操作。在 Golang 里有专门的方法来实现锁,就是 sync 包,这个包有两个很重要的锁类型。一个叫 Mutex, 利用它可以实现互斥锁。一个叫 RWMutex,利用它可以实现读写锁。

全局锁 sync.Mutex,是同一时刻某一资源只能上一个锁,此锁具有排他性,上锁后只能被此线程使用,直至解锁。加锁后即不能读也不能写。全局锁是互斥锁,即 sync.Mutex 是个互斥锁。

读写锁 sync.RWMutex ,将使用者分为读者和写者两个概念,支持同时多个读者一起读共享资源,但写时只能有一个,并且在写时不可以读。理论上来说,sync.RWMutex 的 Lock() 也是个互斥锁。

踩坑点

将上面的结论展开一下,更清晰得说(为避免理解偏差宁可唠叨一些):

  • sync.Mutex 的锁是不可以嵌套使用的。
  • sync.RWMutex 的 mu.Lock() 是不可以嵌套的。
  • sync.RWMutex 的 mu.Lock() 中不可以嵌套 mu.RLock()。(这是个注意的地方)

否则,会 panic fatal error: all goroutines are asleep - deadlock!

var l sync.RWMutexfunc lockAndRead() { // 可读锁内使用可读锁l.RLock()defer l.RUnlock()l.RLock()defer l.RUnlock()
}func main() {lockAndRead()time.Sleep(5 * time.Second)
}

而将 lockAndRead 换为以下三种函数均会造成 panic:

func lockAndRead1() { // 全局锁内使用全局锁l.Lock()defer l.Unlock()l.Lock()defer l.Unlock()
}func lockAndRead2() { // 全局锁内使用可读锁l.Lock()defer l.Unlock() // 由于 defer 是栈式执行,所以这两个锁是嵌套结构l.RLock()defer l.RUnlock()
}func lockAndRead3() { // 可读锁内使用全局锁l.RLock()defer l.RUnlock()l.Lock()defer l.Unlock()
}

互斥锁 Mutex

互斥锁有两个方法:加锁、解锁。

一个互斥锁只能同时被一个 goroutine 锁定,其它 goroutine 将阻塞直到互斥锁被解锁(重新争抢对互斥锁的锁定)。使用Lock加锁后,不能再进行加锁,只有当对其进行Unlock解锁之后,才能对其加锁。这个很好理解。

  • 如果对一个未加锁的资源进行解锁,会引发panic异常。
  • 可以在一个goroutine中对一个资源加锁,而在另外一个goroutine中对该资源进行解锁。
  • 不要在持有锁的时候做 IO 操作。尽量只通过持有锁来保护 IO 操作需要的资源而不是 IO 操作本身
func (m *Mutex) Lock()
func (m *Mutex) Unlock()

读写锁 RWMutex

读写锁有四个方法:读的加锁、解锁,写的加锁、解锁。


func  (*RWMutex)Lock()
func (*RWMutex)Unlock()
和
func (*RWMutex)RLock()
func (*RWMutex)RUnlock()

RWMutex的使用主要事项

  • 1、读锁的时候无需等待读锁的结束
  • 2、读锁的时候要等待写锁的结束
  • 3、写锁的时候要等待读锁的结束
  • 4、写锁的时候要等待写锁的结束

谨防锁拷贝

type MyMutex struct {count intsync.Mutex
}func main() {var mu MyMutexmu.Lock()var mu1 = mumu.count++mu.Unlock()mu1.Lock()mu1.count++mu1.Unlock()fmt.Println(mu.count, mu1.count)
}

加锁后复制变量,会将锁的状态也复制,所以 mu1 其实是已经加锁状态,再加锁会死锁

查看数据竞争

加上 -race 参数验证数据竞争

以下代码有什么问题,怎么解决?

func main() {total, sum := 0, 0for i := 1; i <= 10; i++ {sum += igo func() {total += i}()}fmt.Printf("total:%d sum %d", total, sum)
}

该题的第二个考点:data race。因为存在多 goroutine 同时写 total 变量的问题,所以有数据竞争。可以加上 -race 参数验证

go run -race main.go
==================
WARNING: DATA RACE
Read at 0x00c0001b4020 by goroutine 8:main.main.func1()/Users/xuxinhua/main.go:12 +0x57Previous write at 0x00c0001b4020 by main goroutine:main.main()/Users/xuxinhua/main.go:9 +0x10bGoroutine 8 (running) created at:main.main()/Users/xuxinhua/main.go:11 +0xe7
==================

正确答案

package mainimport ("sync/atomic""sync""fmt"
)func main() {var wg sync.WaitGroupvar total int64sum := 0for i := 1; i <= 10; i++ {wg.Add(1)sum += igo func(i int) {defer wg.Done()atomic.AddInt64(&total, int64(i))}(i)}wg.Wait()fmt.Printf("total:%d sum %d", total, sum)
}

Golang 的锁机制相关推荐

  1. Golang的锁机制

    Golang 中的锁 Golang 中的有两种锁,为 sync.Mutex 和 sync.RWMutex. sync.Mutex 互斥锁,只有一种锁:Lock(),它是绝对锁,同一时间只能有一个锁. ...

  2. mysql三锁,mysql锁机制之表锁(三)

    顾名思义,表锁就是一锁锁一整张表,在表被锁定期间,其他事务不能对该表进行操作,必须等当前表的锁被释放后才能进行操作.表锁响应的是非索引字段,即全表扫描,全表扫描时锁定整张表,sql语句可以通过执行计划 ...

  3. mysql 自旋锁,golang 自旋锁

    CAS算法(compare and swap) CAS算法是一种有名的无锁算法.无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步( ...

  4. 【java线程】锁机制:synchronized、Lock、Condition

    [Java线程]锁机制:synchronized.Lock.Condition 原创 2013年08月14日 17:15:55 标签:Java /多线程 74967 http://www.infoq. ...

  5. Linux内核中锁机制之完成量、互斥量

    在上一篇博文中笔者分析了关于信号量.读写信号量的使用及源码实现,接下来本篇博文将讨论有关完成量和互斥量的使用和一些经典问题. 八.完成量 下面讨论完成量的内容,首先需明确完成量表示为一个执行单元需要等 ...

  6. MySQL优化篇:锁机制

    文章目录 1.概述 1.1 定义 1.2 分类 2.表锁(偏向于读操作) 2.1 特点 2.2 案例分析 2.3 案例结论 2.4 表锁分析 3.行锁(偏向于写操作) 3.1 特点 3.2 案例分析 ...

  7. 数据库锁机制为什么很重要?

    前言 在座的朋友们,你们的时间够用吗?想要成为一个成功的人吗?如果你们都有这样的疑惑,那就保持一刻谦虚的心态,跟着罗老师学习时间管理吧! 毕竟时间管理大师是一个用户访问多个资源,今天咱们来讲讲当多个用 ...

  8. 一文带你了解 MySQL 中的各种锁机制!

    MySQL中的锁机制,按粒度分为行级锁,页级锁,表级锁,其中按用法还分为共享锁和排他锁. 行级锁 行级锁是Mysql中锁定粒度最细的一种锁,表示只针对当前操作的行进行加锁. 行级锁能大大减少数据库操作 ...

  9. 大厂面试官必问的Mysql锁机制

    前言 前几天有粉丝和我聊到他找工作面试大厂时被问的问题,因为现在疫情期间,找工作也特别难找.他说面试的题目也比较难,都偏向于一两年的工作经验的面试题. 他说在一面的时候被问到Mysql的面试题,索引那 ...

最新文章

  1. 被黑客们使用的代码混淆技术
  2. mysql子查询为什么不走索引_解决MySQL中IN子查询会导致无法使用索引问题
  3. 每日一皮:产品和开发在线上吵了许久...
  4. 【白话机器学习】算法理论+实战之PageRank算法
  5. 花旗看好互联网板块 力荐Facebook等5支网络股
  6. LeetCode-best time to buy and sell stock 2 数组
  7. c语言学籍管理系统小程序,学籍业务办理系统(开源 v2.0发布 优化代码,增加小程序端)...
  8. 六级词汇打卡第一天(一)
  9. 代码规范利器-阿里代码规范插件
  10. python使用百度翻译api
  11. IPV4怎么转换成IPV6?
  12. 小米台灯突然自己亮了_除了彩屏和小爱,还有哪些升级?——小米手环4 NFC版...
  13. [HAOI2007]理想的正方形(单调队列)
  14. 分类任务中的类别不平衡问题
  15. 湖南人与江西人,关系有多密切?回顾四省填湘的历史
  16. AI训练环境-CUDA/cuDNN/paddle ——‘CUBLAS_STATUS_INVALID_VALUE‘.
  17. linux桌面显示我的电脑,Windows服务器如何显示”我的电脑”图标 [多种方法详细介绍]...
  18. 泰森多边形(Voronoi diagram)
  19. sha算法 哈希算法_SHA1哈希算法教程及其用法示例
  20. 软工实践 - 第六次作业

热门文章

  1. 从零开始做单相逆变电源(硬件)
  2. 剑指offer 代码实现 C++
  3. Unity 关于MatchVS使用static类型导致GameObject.Find与Action等不可用的解决方法
  4. 对js函数的初步认识 对乘法表简单改进
  5. ALLEGRO等长时如何将PIN DELAY和VIA长度计算在内
  6. 电磁流量计的工作原理及特点
  7. m在simulink进行DS-CDMA建模,然后通过MATLAB调用simulink模型进行误码率仿真
  8. 2012-3-15 《笔记本维护与故障诊断》读书笔记 1
  9. php 除法,php除法函数有哪些
  10. java OA办公自动化系统毕业设计