[转]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不 ...
随机推荐
- H5新人福音~零配置搭建现代化的前端工程
X-BUILD一套基于Webpack(v4.21.0)快速搭建H5场景开发环境的脚手架,只需要几分钟的时间就可以运行起来.X-BUILD是针对H5开发的一套自动化构建工具,致力于提升开发效率,减小开发 ...
- Web框架之Django_05 模型层了解(单表查询、多表查询、聚合查询、分组查询)
摘要: 单表查询 多表查询 聚合查询 分组查询 一.Django ORM 常用字段和参数: 常用字段:#AutoFieldint自增列,必须填入参数primary_key = True,当model中 ...
- LeetCode 637. Average of Levels in Binary Tree(层序遍历)
Given a non-empty binary tree, return the average value of the nodes on each level in the form of an ...
- ES6(Module模块化)
模块化 ES6的模块化的基本规则或特点: 1:每一个模块只加载一次, 每一个JS只执行一次, 如果下次再去加载同目录下同文件,直接从内存中读取. 一个模块就是一个单例,或者说就是一个对象: 2:每一个 ...
- Python (Page Object实例)
Page Object是Selenium自动化测试项目开发实践的最佳设计模式之一,通过对界面元素和功能模块的封装减少冗余代码,同时在后期维护中,若元素定位或功能模块发生变化,只需要调整页面元素或功能模 ...
- mongodb权限机制以及扩展
mongodb权限机制 启动权限机制之前要先在MONGODB中添加管理员账号: 1. 创建账号 重装安装一个mongodb,安装时添加一个 --auth参数: 先把安装好的从服务中删除掉(删除之后数据 ...
- NOIP一系列模拟赛小结
NOIP越发接近了,于是自己也跟着机房的几位师兄一起做了几次NOIP模拟赛,收获颇多. #1-T1:求点集中的点能否只用三条与坐标轴平行的直线就能全部被经过,其实只要将横纵坐标排序后逐个点检查下就行. ...
- [BZOJ4776] [Usaco2017 Open]Modern Art(差分 + 思维?)
传送门 可以预处理出每种颜色的上下左右的位置,这样就框出来了一个个矩形,代表每种颜色分别涂了哪里. 然后用二维的差分. 就可以求出来每个位置至少涂了几次,如果 > 1 的话,就肯定不是先涂的, ...
- SGU 275 To xor or not to xor【最大xor和 高斯消元】
题目大意:给你n个数(n<=100)要你找出若干个数使他们的异或和最大 思路:高斯-若当消元消完以后削成若干个独立的行向量,将它们异或起来就好 #include<cstdio> #i ...
- 刷题总结——烽火传递(单调队列+dp)
题目: 题目描述 烽火台又称烽燧,是重要的防御设施,一般建在险要处或交通要道上.一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息:夜晚燃烧干柴,以火光传递军情.在某两座城市之间有 n 个烽火台,每个烽火 ...