• 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开始抢锁
    ",index)
    
    			//抢锁,如果成功,继续向下执行,否则阻塞等待至抢到为止(抢到的人不释放,你就一直阻塞)
    			//所有抢锁的协程都是资源竞争者
    			mt.Lock()
    
    			/*抢锁成功以后执行对数据的访问*/
    			fmt.Printf("协程%d抢锁成功!
    ",index)
    			fmt.Printf("协程%d开始操作数据!
    ",index)
    			for j := 0; j < 10000; j++ {
    				money +=1
    			}
    			<-time.After(2*time.Second)
    			fmt.Printf("协程%d将锁释放!
    ",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")
    }
    

      

  • 相关阅读:
    微软WP7本地数据库之Sqlite编程技巧(转)
    AutoResetEvent详解
    桥接模式的简单分析
    解决VS2008 调试启动特别慢
    软件概要设计
    解决windows8不能安装ZUNE的问题
    CDATA的对特殊字符作用说明
    DataTable对象在内存中的使用(二)
    DataTable对象在内存中的使用(一)
    关于MVC3 CODE FIRST的安装
  • 原文地址:https://www.cnblogs.com/yunweiqiang/p/12771237.html
Copyright © 2020-2023  润新知