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. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stu' defined in class path resource [applicationContext.xml]: Instantiation of bean failed; nested exception is

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'stu' defined ...

  2. MySQL的Blob类型的手工编辑(manually edit)

    https://dba.stackexchange.com/questions/17593/in-mysql-how-to-manually-edit-values-of-a-blob-column- ...

  3. phpstorm 注释模板

    /** * Created by ${PRODUCT_NAME}. * User: ${USER} * Date: ${DATE} * Time: ${TIME} */

  4. zlib 简单封装

    下列代码用于压缩和解压字符串,使用标准库string.实现了对zlib的简单封装. #pragma once #include <boost/noncopyable.hpp> #inclu ...

  5. Coding Contest HDU - 5988(费用流)

    题意: 有n个区域和m条路,每个区域有a[i]个人和b[i]个食物,然后是m条路连接两个区域,这条路容量为cap,这条路断掉的概率为p,第一个经过的时候一定不会断,后面的人有概率p会断,现在需要所有人 ...

  6. 【BZOJ1823】[JSOI2010]满汉全席(2-sat)

    [BZOJ1823][JSOI2010]满汉全席(2-sat) 题面 BZOJ 洛谷 题解 很明显的\(2-sat\)模板题,还不需要输出方案. 对于任意两组限制之间,检查有无同一种石材要用两种不同的 ...

  7. 牛客练习赛 小A与任务 解题报告

    小A与任务 链接: https://ac.nowcoder.com/acm/contest/369/B 来源:牛客网 题目描述 小A手头有 \(n\) 份任务,他可以以任意顺序完成这些任务,只有完成当 ...

  8. 最长公共子序列LCS(POJ1458)

    转载自:https://www.cnblogs.com/huashanqingzhu/p/7423745.html 题目链接:http://poj.org/problem?id=1458 题目大意:给 ...

  9. ORMLite学习入门笔记

    ORMLite学习入门笔记 使用原始的SQLiteHelper来操作维护数据库有点过于繁琐,重复工作量较大.所以会想到使用一个比较方便的ORM来维护我们本地的数据库,各位业界前辈都给我推荐了ORMLi ...

  10. 洛谷P2446 大陆争霸

    这是一道dijkstra拓展......不知道为什么被评成了紫题. 有一个很朴素的想法就是每次松弛的时候判断一下那个点是否被保护.如果被保护就不入队. 然后发现写起来要改的地方巨多无比...... 改 ...