golang锁包:https://studygolang.com/pkgdoc

sync.Mutex是一个互斥锁

var lock sync.Mutex

加锁段在中

lock.lock()

lock.unlock()

sync.RWMutex为读写锁。使用方法同互斥锁

package main

import (
"fmt"
) func main() {
var a = 1 go func(num *int) {
for n := 0; n < 1000; n++ {
*num++
}
}(&a) go func(num1 *int) {
for i := 0; i < 1000; i++ {
*num1++
}
}(&a) fmt.Println(a)
}

发现执行结果输出为1,原因为主进程在创建完子线程后就结束了。子线程还未执行。也就没有对变量a进程运算

使用sync.WaitGroup等待子线程结束后退出。

package main

import (
"fmt"
"sync"
) func main() {
var a int
var wg sync.WaitGroup
wg.Add(2)
go func(num *int) {
for n := 0; n < 100000; n++ {
*num++
}
wg.Done()
}(&a) go func(num1 *int) {
for i := 0; i < 100000; i++ {
*num1++ }
wg.Done()
}(&a)
wg.Wait()
fmt.Println(a)
}

在运行多次后发现并不等于200000,而且每次都不同,原因为线程1在操作a变量时变量为0,运算的1,在运算过程中,线程b也读取a变量此时a还为1,也就造就了运算结果不一致问题。

此时就需要使用锁,sync.Mutex

package main

import (
"fmt"
"sync"
) func main() {
var a int
var wg sync.WaitGroup
var lock sync.Mutex
wg.Add(2)
go func(num *int) {
for n := 0; n < 100000; n++ {
lock.Lock()
*num++
lock.Unlock()
}
wg.Done()
}(&a) go func(num1 *int) {
for i := 0; i < 100000; i++ {
lock.Lock()
*num1++
lock.Unlock()
}
wg.Done()
}(&a)
wg.Wait()
fmt.Println(a)
}

执行多次后结果都是唯一的。

数据竞争

func RWlock() {
var a int go func(num *int) {
for n := 0; n < 100000; n++ {
*num++
}
}(&a)
fmt.Println("------", a)
} func main() {
RWlock()
}

编译后执行,提示wirte 线程goroutine 6 与读进程 goroutine main有数据冲突

C:\Users\LC>C:\Users\LC\lock2.exe
------ 0
==================
WARNING: DATA RACE
Write at 0x00c000058058 by goroutine 6:
main.RWlock.func1()
D:/go_work/src/lock/lock2/lock1.go:14 +0x72 Previous read at 0x00c000058058 by main goroutine:
main.RWlock()
D:/go_work/src/lock/lock2/lock1.go:19 +0xd1
main.main()
D:/go_work/src/lock/lock2/lock1.go:23 +0x36 Goroutine 6 (running) created at:
main.RWlock()
D:/go_work/src/lock/lock2/lock1.go:11 +0xc3
main.main()
D:/go_work/src/lock/lock2/lock1.go:23 +0x36
==================
Found 1 data race(s)

在读的地方也加上锁后

lock.Lock()
fmt.Println("------", a)
lock.Unlock()
C:\Users\LC>go build -race lock\lock2

C:\Users\LC>C:\Users\LC\lock2.exe
------ 0

读写锁

读只对共享资源进行读操作,写只对共享资源进行写操作,使用场景,在读多写少时,加互斥锁性能较低,第一个读进行操作时,第二个读进程在等待,他们之间互斥。此时加上读写锁后,第一个线程加上读锁时,后面的资源都可以进行操作。

package main

import (
"fmt"
"sync"
"sync/atomic"
"time"
) func rwLock() {
var counts uint32
var lock sync.Mutex
// var lock sync.RWMutex
var num int
for n := 0; n < 3; n++ { //创建3个写线程
go func(number *int) {
lock.Lock()
*number++
time.Sleep(10 * time.Millisecond)
lock.Unlock()
}(&num)
}
for n := 0; n < 100; n++ { //创建100个读线程
go func(number *int) {
for { //每个线程死循环无限读,
// lock.RLock()
lock.Lock()
// fmt.Println(*number)
time.Sleep(time.Millisecond * 3)
lock.Unlock()
// lock.RUnlock()
atomic.AddUint32(&counts, 1) //记录读的次数
}
}(&num)
} time.Sleep(time.Second * 3) //主进程总共执行时间3秒,即3秒内互斥锁和读写锁在读方面可执行多少次
fmt.Println(atomic.LoadUint32(&counts)) //获取读的总次数
} func main() {
rwLock()
}

将读写锁改为互斥锁后,本次测试的次数相差很多

golang锁的更多相关文章

  1. golang锁记

    golang中有两个锁实现 atomic的CAS实现锁 首先是inter cpu,熟悉汇编的人都知道,inter指令集有个lock,如果某个指令集前面加个lock,那么在多核状态下,某个核执行到这个前 ...

  2. 详解golang net之netpoll

    golang版本1.12.9:操作系统:readhat 7.4 golang的底层使用epoll来实现IO复用.netPoll通过pollDesc结构体将文件描述符与底层进行了绑定.netpoll实现 ...

  3. golang 互斥锁和读写锁

    golang 互斥锁和读写锁 golang中sync包实现了两种锁Mutex(互斥锁)和RWMutex(读写锁),其中RWMutex是基于Mutex实现的,只读锁的实现使用类似引用计数器的功能. ty ...

  4. 使用Golang利用ectd实现一个分布式锁

    http://blog.codeg.cn/post/blog/2016-02-24-distrubute-lock-over-etcd/ By zieckey · 2016年02月24日 · 1205 ...

  5. Golang 读写锁RWMutex 互斥锁Mutex 源码详解

    前言 Golang中有两种类型的锁,Mutex (互斥锁)和RWMutex(读写锁)对于这两种锁的使用这里就不多说了,本文主要侧重于从源码的角度分析这两种锁的具体实现. 引子问题 我一般喜欢带着问题去 ...

  6. golang 并发锁的陷阱

    错误代码示例 package main import ( "sync" "strconv" "fmt" ) type Node struct ...

  7. Golang 入门系列(十六)锁的使用场景主要涉及到哪些?读写锁为什么会比普通锁快

    前面已经讲过很多Golang系列知识,感兴趣的可以看看以前的文章,https://www.cnblogs.com/zhangweizhong/category/1275863.html, 接下来要说的 ...

  8. golang中锁mutex的实现

    golang中的锁是通过CAS原子操作实现的,Mutex结构如下: type Mutex struct {     state int32                     sema  uint ...

  9. 一道并发和锁的golang面试题

    今天面试golang碰到了一道考并发和锁的题目,没有完成,所以把它记录下来,仅为以后复习. 场景:在一个高并发的web服务器中,要限制IP的频繁访问.现模拟100个IP同时并发访问服务器,每个IP要重 ...

随机推荐

  1. PAT L3-008 喊山

    https://pintia.cn/problem-sets/994805046380707840/problems/994805050709229568 喊山,是人双手围在嘴边成喇叭状,对着远方高山 ...

  2. PAT 1083 是否存在相等的差

    https://pintia.cn/problem-sets/994805260223102976/problems/994805260780945408 给定 N 张卡片,正面分别写上 1.2.…… ...

  3. 使用docker-compose 大杀器来部署服务

    使用docker-compose 大杀器来部署服务 上 我们都听过或者用过 docker,然而使用方式却是仅仅用手动的方式,这样去操作 docker 还是很原始. 好吧,可能在小白的眼中噼里啪啦的对着 ...

  4. [转帖]Tensor是神马?为什么还会Flow?

    Tensor是神马?为什么还会Flow? 互联网爱好者 百家号17-05-2310:03 大数据文摘作品,转载要求见文末 编译 | 邵胖胖,江凡,笪洁琼,Aileen 也许你已经下载了TensorFl ...

  5. Jquery ajax load(),get(),post()

    //load()用来加载html文档中的代码片段,添加到指定元素内部 //如果只加部分选定的元素可以.load("url 选择器") <!DOCTYPE html>&l ...

  6. Axure8.0从入门到精通

    1. 新建工程 菜单->File->New 2. 添加组件并编辑组件 选中左侧Libary可选择Default/Flow/Icons,找到相应的组件并移动到工作区:并在右侧选中相应的组件属 ...

  7. 跪求delphi 中的bitbutton 中的bmp图标

    C:\Program Files (x86)\Embarcadero\RAD Studio\11.0\Images\GlyFX

  8. char类型的数值转换

    在视频教程中,你已经认识到了数字类型之间.字符串和其他类型之间的转换.而某些时候,我们还需要将char类型转换为int类型,或者把int类型转换为char类型. 这篇文章,将介绍在代码中虽然不太常用, ...

  9. BZOJ1901Zju2112 Dynamic Rankings——树状数组套主席树

    题目描述 给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1 ],a[i+2]……a[j]中第k小的数是多少(1≤k ...

  10. BZOJ2001 HNOI2010城市建设(线段树分治+LCT)

    一个很显然的思路是把边按时间段拆开线段树分治一下,用lct维护MST.理论上复杂度是O((M+Q)logNlogQ),实际常数爆炸T成狗.正解写不动了. #include<iostream> ...