Go语言协程并发---互斥锁sync.Mutex

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")
}

  

posted @ 2020-04-25 00:45  Ethan_Cheng  阅读(590)  评论(0编辑  收藏  举报