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. 记一次“愉快”的lnmp环境的搭建

    愉快的lnmp环境搭建 后续更新 几个笔记记录 yum remove php-mysql yum -y install cmake autoconf wget gcc-c++ gcc zlib pcr ...

  2. Sublime text3 的安装【解决官网被墙问题】

    使用提示 主要是https://packagecontrol.io 这个被墙了 下载不下来导致的错误,把下载链接改为国内的:修改sublime text3的package setting 的user配 ...

  3. CentOS7用yum安装软件提示 cannot find a valid baseurl for repobase7x86_64

    解决办法[亲测有效] 1.打开 vi /etc/sysconfig/network-scripts/ifcfg-enp4s0(每个机子都可能不一样,但格式会是"ifcfg-e..." ...

  4. Android so注入( inject)和Hook(挂钩)的实现思路讨论

    本文博客:http://blog.csdn.net/qq1084283172/article/details/54095995 前面的博客中分析一些Android的so注入和Hook目标函数的代码,它 ...

  5. 开启Android Apk调试与备份选项的Xposed模块的编写

    本文博客地址:https://blog.csdn.net/QQ1084283172/article/details/80963610 在进行Android应用程序逆向分析的时候,经常需要进行Andro ...

  6. Linux启动流程和服务管理(init和systemd)

    目录 一:Linux启动流程 init和Systemd的区别 二:Linux服务管理(service,systemctl) 一:Linux启动流程 Rhel6启动过程: Rhel7启动过程: GRUB ...

  7. Windows核心编程 第26章 窗口消 息

    窗 口 消 息 Wi n d o w s允许一个进程至多建立10 000个不同类型的用户对象(User object):图符.光标.窗口类.菜单.加速键表等等.当一个线程调用一个函数来建立某个对象时, ...

  8. openstack虚拟机从数据库修改卷虚拟机backend操作

    由于意外故障,volume-type其中一个backend后段出现性能问题,客户云主机出现卡顿. 因此临时从ceph将系统卷导出,并导入至同一个backend的另一个后端,并启动虚拟机. Nova C ...

  9. 一起来看看java并发中volatile关键字的神奇之处

    并发编程中的三个概念: 1.原子性 在Java中,对基本数据类型的变量的读取和赋值操作是原子性操作,即这些操作是不可被中断的,要么执行,要么不执行. 2.可见性 对于可见性,Java提供了volati ...

  10. 【python】Leetcode每日一题-不同的子序列

    [python]Leetcode每日一题-不同的子序列 [题目描述] 给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数. 字符串的一个 子序列 是指,通过删除一些(也可以 ...