package main

import (
"fmt"
"sync"
"time"
) /*
mt.Lock()
抢锁
一次只能被一个协程锁住
其余想要抢到这把锁的协程阻塞等待至前面的协程将锁释放
mt.Lock()的可能性有两种:
①抢到锁,继续向下执行
②没抢到,阻塞等待至前面的协程将锁释放
-------------------------------------------
mt.Unlock()
解锁
锁一旦释放,其他抢这把锁的协程就会得到抢锁机会
*/ func main() {
//声明同步锁
var mt sync.Mutex var wg sync.WaitGroup
var money = 2000 for i := 0; i < 10; i++ {
wg.Add(1)
go func(index int) {
fmt.Printf("协程%d开始抢锁\n",index) //抢锁,如果成功,继续向下执行,否则阻塞等待至抢到为止(抢到的人不释放,你就一直阻塞)
//所有抢锁的协程都是资源竞争者
mt.Lock() /*抢锁成功以后执行对数据的访问*/
fmt.Printf("协程%d抢锁成功!\n",index)
fmt.Printf("协程%d开始操作数据!\n",index)
for j := 0; j < 10000; j++ {
money +=1
}
<-time.After(2*time.Second)
fmt.Printf("协程%d将锁释放!\n",index) //数据操作完毕,将锁释放
mt.Unlock()
wg.Done()
}(i)
}
wg.Wait()
fmt.Println(money)
}

  

一个互斥锁的小案例:

package main

import (
"fmt"
"sync"
"time"
) /*
银行账户案例
·创建银行类账户
·存取款方式需要并发安全(不允许并发访问余额)
·查询余额和打印流水可以并发操作
·创建账户实例,并发执行存取款,查询余额,打印流水操作
*/ type Account struct{
money int //账户的互斥锁
mt sync.Mutex
} /*
存钱:必须保证并发安全,不允许并发操作
*/
func (a *Account)SaveMoney(n int) {
//必须先抢到互斥锁
a.mt.Lock() fmt.Println("SaveMoney开始")
<-time.After(3*time.Second)
a.money += n
fmt.Println("SaveMoney结束") //将锁释放
a.mt.Unlock()
} /*
取钱:必须保证并发安全,不允许并发操作
*/
func (a *Account)GetMoney(n int) {
//必须先抢到互斥锁
a.mt.Lock() fmt.Println("GetMoney开始")
<-time.After(3*time.Second)
a.money -= n
fmt.Println("GetMoney结束") //将锁释放
a.mt.Unlock()
} /*查询余额:可以并发执行*/
func (a *Account)Query() {
fmt.Println("Query开始")
<-time.After(3*time.Second)
fmt.Println("当前余额:",a.money)
fmt.Println("Query结束")
} ///*打印流水:可以并发执行*/
//func (a *Account)PrintHistory() {
// fmt.Println("PrintHistory开始")
// <-time.After(3*time.Second)
// fmt.Println("打印流水")
// fmt.Println("PrintHistory结束")
//} func main() {
var wg sync.WaitGroup account := &Account{10000, sync.Mutex{}} for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
account.SaveMoney(100)
wg.Done()
}() } for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
account.GetMoney(100)
wg.Done()
}()
} for i := 0; i < 3; i++ {
wg.Add(1)
go func() {
account.Query()
wg.Done()
}()
} //for i := 0; i < 3; i++ {
// wg.Add(1)
// go func() {
// account.PrintHistory()
// wg.Done()
// }()
//} wg.Wait() fmt.Println("main over")
}

  

Go语言协程并发---互斥锁sync.Mutex的更多相关文章

  1. Go语言协程并发---读写锁sync.RWMutex

    package main import ( "fmt" "sync" "time" ) /* 读写锁 多路只读 一路只写 读写互斥 */ / ...

  2. Go语言协程并发---等待组sync.WaitGroup

    package main import ( "fmt" "sync" "time" ) /*等待组API介绍*/ func main071( ...

  3. Go语言协程并发---管道信号量应用

    package main import ( "fmt" "math" "strconv" "time" ) /* ·10 ...

  4. Go语言协程并发---条件变量

    package main import ( "fmt" "sync" "time" ) func main() { //要监听的变量 bit ...

  5. Go语言协程并发---生产者消费者实例

    package main import ( "fmt" "strconv" "time" ) /* 改进生产者消费者模型 ·生产者每秒生产一 ...

  6. Go语言协程并发---原子操作

    package main import ( "fmt" "sync/atomic" ) /* 用原子来替换锁,其主要原因是: 原子操作由底层硬件支持,而锁则由操 ...

  7. Go语言协程并发---timer秒表与定时器

    秒表 package main import ( "fmt" "time" ) /*每秒大喊我要去浪,共9次,然后退出计时*/ func main() { va ...

  8. Go语言协程并发---select多路复用应用

    package main import ( "fmt" "time" ) /* ·循环从一写两读三条管道中随机选择一条能走的路 ·等所有路都走不通了就退出循环 ...

  9. Go语言协程

    协程的特点 1.该任务的业务代码主动要求切换,即主动让出执行权限 2.发生了IO,导致执行阻塞(使用channel让协程阻塞) 与线程本质的不同 C#.java中我们执行多个线程,是通过时间片切换来进 ...

随机推荐

  1. Python爬取笔趣阁小说,有趣又实用

    上班想摸鱼?为了摸鱼方便,今天自己写了个爬取笔阁小说的程序.好吧,其实就是找个目的学习python,分享一下. 1. 首先导入相关的模块 import os import requests from ...

  2. URL中字符的含义

    目录 URL中的特殊字符 #号的作用 URL中的特殊字符 我们经常会看到URL中有一些特殊的字符,比如 #,?,& ,/ ,+ 等.那么,它们的含义是什么呢? 特殊含义 十六进制 + 表示空格 ...

  3. 通过使用 NTLite 工具实现精简Windows系统

    NTLite 是一款专业于Windows平台的系统精简工具,NTLite主要面对系统封装人员使用,比如各大下载站及GHO镜像下载站,Windows系统二次精简封装打包使用,NTLite可以对系统进行极 ...

  4. Linux-鸟菜-6-文件与目录管理

    Linux-鸟菜-6-文件与目录管理 这章主要是说一些对目录和文件的增删改查等等命令. .    代表当前目录 ..    代表前一个目录   / 的 . 和 .. 一样 -    代表前一个工作目录 ...

  5. 【js】Leetcode每日一题-数组异或操作

    [js]Leetcode每日一题-数组异或操作 [题目描述] 给你两个整数,n 和 start . 数组 nums 定义为:nums[i] = start + 2*i(下标从 0 开始)且 n == ...

  6. Arduino+DS18b20+OLED Display

    DS18b20获取到温度数值保存到变量中,然后和天气图标还有滚动字幕一起发送到OLED 屏幕上显示 需要用到的库均可在Arduino库管理器下载. 电路图: 图中屏幕接线已在代码中写出,温度传感器da ...

  7. 【前端】vue2.x 配合 bootstrapTable 动态添加元素和绑定点击事件,事件无效 解决

    背景: 使用bootstrap-table 表格插件时,每一行的最后一班会加操作按钮列.如果不加入vue的话,使用插件自己的列属性formatter:function(value, row, inde ...

  8. 使用C#进行数据库增删改查ADO.NET(二)

    这节接着讲用C#进行数据库CRUD,高级部分.  事务: 事务是执行一批sql语句,如果中途失败,全部回滚,数据不会受影响,中途没有出错则会提交事务,真正对数据进行修改.C#提供了SqlTransac ...

  9. Python中的pip安装与使用

    配置python的环境变量 我们在我的电脑右击->属性->高级系统设置看到环境变量 然后我们点击环境变量,找到系统变量中的Path变量然后双击他新建一项,值为我们安装的python的pyt ...

  10. [bug] CDH 安装 Error : No matching Packages to list

    信息 分析 我的系统是CentOS 7,而 cm 安装包是配合 redhat 6 的,应该选择 redhat 7 目录下的包 参考 https://community.cloudera.com/t5/ ...