[转]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不 ...
随机推荐
- windows2012安装sql2012报错
一. 处理
- 如何用纯 CSS 创作一个菱形 loader 动画
效果预览 在线演示 按下右侧的"点击预览"按钮可以在当前页面预览,点击链接可以全屏预览. https://codepen.io/comehope/pen/eKzjqK 可交互视频教 ...
- mbist summary
1. 关于mbist,网上也有介绍,觉得不错: 推荐的mbistt的博客:奋斗的猪 2.使用的工具是mbistarchitect,不是tessent. 3.工具使用的相关文档:从EETOP和工具自带的 ...
- Makefile学习(二)----生成静态库文件
Lunix下编译静态库文件: .o后缀文件:编译生成的中间代码文件: .a后缀文件:静态库文件,编译的时候会合到可执行程序中,文件比较大: .so后缀文件:动态库文件,只是一个指向,不会合到可执行程序 ...
- Python 编程要求
1.添加前缀 #!/usr/bin/env python # -*- coding:utf-8 -*- 2.py文件.函数都要写好注释 3.主函数要加上判断 if __name__ == " ...
- Web Best Practices
Web Best Practices General Google WebFundamentals - Github JavaScript Style Guide - Github Google In ...
- loj2002 「SDOI2017」序列计数
水题 #include <iostream> #include <cstring> #include <cstdio> using namespace std; t ...
- Mac版有道云笔记不能自动同步
删除本地资源文件夹 /Users/xxxx/Library/Containers/com.youdao.note.YoudaoNoteMac 直接删除整个文件夹,之后重新登录账号.
- hdu 1848 sg——dfs&&打表双实现
Fibonacci again and again Time Limit: 1000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Jav ...
- EXPDP/IMPDP任务的查看与管理
EXPDP/IMPDP相比传统的exp/imp的最本质区别在于服务器端执行,客户端发出指定后,通过API启动服务器的备份job,在执行过程中,可以拿下Ctrl+C组合键,退出当前交互模式,退出之后,导 ...