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. JavaScript获取DOM节点

    常用的方法有 document.getElementById("id"); document.getElementsByTagName('tagName'); document.g ...

  2. vue-devtools 的安装和使用

    vue-devtools的安装与使用 一.在github上下载压缩包,github下载地址:https://github.com/vuejs/vue-devtools 二.解压到本地的某盘 三.用你的 ...

  3. SAP字体调节大小

    登陆SAP 之后,菜单下面一行,最右边的那个彩色按钮(SAP GUI),点击“选项”-可视设计-字体设计-固定狂赌字体设计,点击:选择字体 即可.

  4. [转] python 模块学习 hashlib

    转自: http://www.cnblogs.com/BeginMan/p/3328172.html 一.hashlib概述 涉及加密服务:14. Cryptographic Services 其中 ...

  5. js對象構造

    創建對象的3種方式: 1. var a=new Object() a.attributes=“1”: 2. var a={attributes:"1",aa:"2&quo ...

  6. 使用nexus搭建maven私服教程详解

    私服是什么 私服,私有服务器,是公司内部Maven项目经常需要的东东,不总结一下,不足以体现出重视.Nexus是常用的私用Maven服务器,一般是公司内部使用.下载地址是http://www.sona ...

  7. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并

    题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...

  8. 【Linux】Screen命令

    1.运行screen [root@master2 ~]# screen 2.执行脚本 [root@master2 ~]# sh mgr.sh 命令帮助 更详细的请使用 man screen查看 htt ...

  9. BZOJ5338 [TJOI2018] Xor 【可持久化Trie树】【dfs序】

    题目分析: 很无聊的一道题目.首先区间内单点对应异或值的询问容易想到trie树.由于题目在树上进行,case1将路径分成两段,然后dfs的时候顺便可持久化trie树做询问.case2维护dfs序,对d ...

  10. BZOJ4870 [六省联考2017] 组合数问题 【快速幂】

    题目分析: 构造f[nk][r]表示题目中要求的东西.容易发现递推公式f[nk][r]=f[nk-1][r]+f[nk-1][(r-1)%k].矩阵快速幂可以优化,时间复杂度O(k^3logn). 代 ...