[转]Go基础之锁的初识
当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢?
- 当我们多个线程在读相同的数据的时候则是需要加锁的
- 当我们的程序既有读又有写的时候更是需要加锁的
- 当我们有多个线程在写的时候同样也是需要加锁
互斥锁
互斥锁:同一个时刻只有一个线程能够拿到锁
我们先通过一个例子来演示,如果当多个线程同时更改一个变量,结果会是怎么样
不加锁版本
package main import (
"sync"
"fmt"
) var (
//lock sync.Mutex
count int
w sync.WaitGroup //用于等待子线程执行完之后退出
) func main() {
w.Add(1) // 在调用线程前执行w.add
go func(){
for i:=0;i<100000;i++{
count++
}
w.Done() //执行完 执行w.Done
}()
for i :=0;i<100000;i++{
count++
}
w.Wait() // 最后执行w.wait等待所有的线程执行完毕
fmt.Println(count) }
当我们运行多次就可以发现,最后的结果基本不可能是我们先看到的:200000
我们修改代码代码需要加锁保护的地方加上锁,并且这里加的是互斥锁,修改后的代码为:
package main import (
"sync"
"fmt"
) var (
lock sync.Mutex
count int
w sync.WaitGroup //用于等待子线程执行完之后退出
) func main() {
w.Add(1) // 在调用线程前执行w.add
go func(){
for i:=0;i<100000;i++{
lock.Lock()
count++
lock.Unlock()
}
w.Done() //执行完 执行w.Done
}()
for i :=0;i<100000;i++{
lock.Lock()
count++
lock.Unlock()
}
w.Wait() // 最后执行w.wait等待所有的线程执行完毕
fmt.Println(count) }
这次当我们多次运行的时候,就能保证我们每次都能看到我们想要的值:200000
接下来看读写锁
读写锁
读写锁主要用到读多写少的场景
读写锁分为:读锁和写锁
如果自己设置了一个写锁,那么其他读的线程以及写的线程都拿不到锁,这个时候和互斥锁的功能相同
如果自己设置了一个读锁,那么其他写的线程是拿不到锁的,但是其他读的线程都是可以拿到这个锁
我们把上面的例子代码进行更改:
package main import (
"sync"
"fmt"
) var (
rwlock sync.RWMutex
w sync.WaitGroup
count int
) func main() {
w.Add(1)
go func(){
for i:=0;i<1000000;i++{
rwlock.Lock() // 这里定义了一个写锁
count++
rwlock.Unlock()
}
w.Done()
}() for i:=0;i<1000000;i++{
rwlock.Lock() // 这里定义了一个写锁
count++
rwlock.Unlock()
}
w.Wait()
fmt.Println(count)
}
通过设置写锁,我们同样可以实现数据的一致性
下面是一个读锁的使用例子:
package main import (
"sync"
"fmt"
) var (
rwlock sync.RWMutex
w sync.WaitGroup
count int
) func main() {
w.Add(1)
go func(){
for i:=0;i<1000000;i++{
rwlock.Lock() // 这里定义了一个写锁
count++
rwlock.Unlock()
}
w.Done()
}() for i:=0;i<16;i++{
w.Add(1)
go func(){
rwlock.RLock() //这里定义了一个读锁
fmt.Println(count)
rwlock.RUnlock() //释放读锁
w.Done()
}()
}
w.Wait()
fmt.Println(count)
}
Go中的原子操作
原子操作,我们则不需加锁,也能保证数据的一致性
并且如果只是计算,那么原子操作则是最快的
实例代码:
package main import (
"sync"
//"time"
"sync/atomic"
"fmt"
) var (
w sync.WaitGroup
count int32
) func main() {
w.Add(1)
//start := time.Now().UnixNano()
go func() {
for i:=0;i<1000000;i++{
atomic.AddInt32(&count,1)
}
w.Done()
}() for i:=0;i<1000000;i++{
atomic.AddInt32(&count,1)
}
w.Wait()
//end := time.Now().UnixNano()
//fmt.Println((end- start)/1000/1000)
fmt.Println(count)
}
[转]Go基础之锁的初识的更多相关文章
- Go基础之锁的初识
当我们的程序就一个线程的时候是不需要用到锁的,但是通常我们实际的代码不会是单个线程的,所有这个时候就需要用到锁了,那么关于锁的使用场景主要涉及到哪些呢? 当我们多个线程在读相同的数据的时候则是需要加锁 ...
- 006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序
006 01 Android 零基础入门 01 Java基础语法 01 Java初识 06 使用Eclipse开发Java程序 Eclipse下创建程序 创建程序分为以下几个步骤: 1.首先是创建一个 ...
- 005 01 Android 零基础入门 01 Java基础语法 01 Java初识 05 Eclipse简介
005 01 Android 零基础入门 01 Java基础语法 01 Java初识 05 Eclipse简介 Eclipse是一款集成开发工具--IDE. 集成开发环境(IDE,Integrated ...
- 004 01 Android 零基础入门 01 Java基础语法 01 Java初识 04 Java程序的结构
004 01 Android 零基础入门 01 Java基础语法 01 Java初识 04 Java程序的结构 Java程序的结构 Java程序外层--类 程序外层,如下面的代码,是一个类的定义. c ...
- 003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程
003 01 Android 零基础入门 01 Java基础语法 01 Java初识 03 Java程序的执行流程 Java程序长啥样? 首先编写一个Java程序 记事本编写程序 打开记事本 1.wi ...
- 002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介
002 01 Android 零基础入门 01 Java基础语法 01 Java初识 02 Java简介 学习Java的基础语法 Java是一门编程语言,学习的逻辑其实和现实世界的语言是一样的,需要了 ...
- 001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学
001 01 Android 零基础入门 01 Java基础语法 01 Java初识 01 导学 welcome to Java World 欢迎来到Java世界 一起领略Java编程世界的奥秘与奥妙 ...
- python学习笔记(基础四:模块初识、pyc和PyCodeObject是什么)
一.模块初识(一) 模块,也叫库.库有标准库第三方库. 注意事项:文件名不能和导入的模块名相同 1. sys模块 import sys print(sys.path) #打印环境变量 print(sy ...
- [转]《Hadoop基础教程》之初识Hadoop
原文地址:http://blessht.iteye.com/blog/2095675 Hadoop一直是我想学习的技术,正巧最近项目组要做电子商城,我就开始研究Hadoop,虽然最后鉴定Hadoop不 ...
随机推荐
- linux内核数据结构
https://blog.csdn.net/zhangskd/article/details/11225301 在看ip_acct.c相关代码时看到大量使用了 hlist_nulls_for_each ...
- C语言获取Shell返回结果
Linux编程时候,如果我们需要调用shell命令或脚本通常使用system方法.如system("ls") 该方法返回值为0或-1,即成功或失败.而有的时候我们想要获取shell ...
- python--MySQL权限管理 数据备份还原
一 权限管理 mysql最高管理者是root用户, 这个一般掌握在公司DBA手里, 当你想去对数据库进行一些操作的时候,需要DBA授权给你. 1. 对新用户增删改 1. 创建用户 # 要先use my ...
- The North American Invitational Programming Contest 2018 H. Recovery
Consider an n \times mn×m matrix of ones and zeros. For example, this 4 \times 44×4: \displaystyle \ ...
- Java的9种基本数据类型以及封装类
Java的9种基本数据类型以及封装类 基本类型 大小(单位/字节) 默认值 封装类 byte 1 (byte)0 Byte short 2 (short)0 Short int 4 0 Integer ...
- SQL Server数据库和MySQL数据库有什么区别?
SQL Server数据库和MySQL数据库有什么区别呢?详细很多初入IT行业的朋友对于SQL Server数据库和MySQL数据库经常搞混,认为这两种数据库是同一种,其实不然,今天我们来分析一下这两 ...
- jenkins之Tomcat7+jdk1.7+jenkins
目的 在开发中,需要经常频繁的对测试服务器进行部署,而且在多人协同中开发经常遇到的问题就是别人更新了他的代码,而你去更新你的代码时并没有更新到别人的代码,导致测试环境的代码不是最新,当然这个问题也好解 ...
- Terracotta服务器的不同配置方式
Terracotta服务器的不同配置方式 博客分类: 企业应用面临的问题 Java&Socket 开源组件的应用 Terracotta双机多机镜像服务器阵列分片模式企业应用 Terracott ...
- 【Luogu】P3381最小费用最大流模板(SPFA找增广路)
题目链接 哈 学会最小费用最大流啦 思路是这样. 首先我们有一个贪心策略.如果我们每次找到单位费用和最短的一条增广路,那么显然我们可以把这条路添加到已有的流量里去——不管这条路的流量是多大,反正它能 ...
- BZOJ 1009 [HNOI2008]GT考试 ——矩阵乘法 KMP
先用KMP处理所有的转移,或者直接暴力也可以. 然后矩阵快速幂即可. #include <cstdio> #include <cstring> #include <ios ...