• Go同步原语


    package main
    
    /**
    同步原语:
    sync.Mutex:互斥锁,指的是同一时刻只有一个携程执行某段代码,其他协程都要等待该协程执行完毕后才能继续执行
    sync.RWMutex:读写锁
    sync.WaitGroup:用于最终完成的场景,关键点一定要等待所有的协程都执行完毕
    sync.Once:只执行一次,调用方法为 var once sync.Once once.Do(函数或方法)
    sync.Cond:用于发号施令,一声令下所有协程都可以开始执行,关键点在于协程开始的时候是等待的,要等待sync.Cond唤醒才能执行
    */
    import (
        "fmt"
        "sync"
        "time"
    )
    
    //共享的资源
    
    var (
        sum int
        //mutex sync.Mutex
        mutex sync.RWMutex
        wg    sync.WaitGroup
    )
    
    func main() {
    
        ////因为要监控110个协程,所以设置计数器为110
        //wg.Add(110)
        ////开启100个协程让sum+10
        //for i := 0; i < 100; i++ {
        //    //go add(10)
        //    go func(i int) {
        //        //计数器值减1
        //        defer wg.Done()
        //        add(i)
        //    }(10)
        //}
        //
        ////启动十个协程用来读
        //for i := 0; i < 10; i++ {
        //    //go fmt.Println("和为:", readSum())
        //    go func() {
        //        //计数器值减1
        //        defer wg.Done()
        //        fmt.Println("和为:", readSum())
        //    }()
        //}
        //
        ////防止提前退出
        ////time.Sleep(2 * time.Second)
        ////一直等待,直到计数器值为0
        //wg.Wait()
        ////fmt.Println("和为:", sum)
        //
        ////在高并发的情况下,sync.Once也会保证onceBody函数只执行一次
        //doOnce()
        race()
    }
    
    func add(i int) {
        mutex.Lock()
        defer mutex.Unlock()
        sum += i
    }
    
    //增加一个读取sum的函数,便于演示并发
    func readSum() int {
        //mutex.Lock()
        //defer mutex.Unlock()
        //只获取读锁
        mutex.RLock()
        defer mutex.RUnlock()
    
        b := sum
        return b
    }
    
    func doOnce() {
    
        var once sync.Once
        onceBody := func() {
            fmt.Println("Only once")
        }
        //用于等待协程执行完毕
        done := make(chan bool)
    
        //启动10个协程执行once.Do(onceBody)
        for i := 0; i < 10; i++ {
            go func() {
                //把要执行的函数(方法)作为参数传递给once.Do方法即可
                once.Do(onceBody)
                done <- true
            }()
        }
        for i := 0; i < 10; i++ {
            <-done
        }
    
    }
    
    /**
    
      执行步骤拆解:
    1.通过 sync.NewCond 函数生成一个*sync.Cond,用于阻塞和唤醒协程
    2.然后启动10个协程模拟10个人,准备就位后调用cond.Wait()方法阻塞当前协程等待发令枪响,这里需要注意的是调用cond.Wait()方法时需要加锁
    3.time.Sleep用于等待所有人都进入wait阻塞状态,这样裁判才能调用cond.Broadcast()发号施令
    4.裁判准备完毕后,就可以调用cond.Broadcast()通知所有人开始跑了
    
    sync.Cond 有三个方法:
    1.Wait,阻塞当前协程,直到被其他协程调用Broadcast或者Signal方法唤醒,使用的时候需要加锁,使用sync.Cond中的锁即可,也就是L字段
    2.Signal,唤醒一个等待时间最长的协程
    3.Broadcast,唤醒所有等待的协程
    注意:在调用Signal或者Broadcast之前,要确保目标协程处于Wait阻塞状态,不然会出现死锁问题
    这里和java的等待唤醒机制很像,它的三个方法Wait、Signal、Broadcast就分别对java中的wait、notify、notifyAll
    */ //10个人赛跑,一个裁判发号施令 func race() { cond := sync.NewCond(&sync.Mutex{}) var wg1 sync.WaitGroup wg1.Add(11) for i := 0; i < 10; i++ { go func(num int) { defer wg1.Done() fmt.Println(num, "号已经就位") cond.L.Lock() cond.Wait() fmt.Println(num, "号开始跑...") cond.L.Unlock() }(i) } //等待所有goroutine都进入wait状态 time.Sleep(2 * time.Second) go func() { defer wg1.Done() fmt.Println("裁判已经到位,准备发令枪") fmt.Println("比赛开始,大家准备跑") cond.Broadcast() //发令枪响 }() //防止函数提前返回退出 wg1.Wait() }
  • 相关阅读:
    Serverless 解惑——函数计算如何安装字体
    构建安全可靠的微服务 | Nacos 在颜铺 SaaS 平台的应用实践
    OAM v1alpha2 新版:平衡标准与可扩展性
    人工智能与阅读能力的关系研究
    Java Web每天学之Servlet的原理解析
    ThreadLocal类的简单使用
    JavaScript之DOM创建节点
    css浮动(float)及清除浮动的几种实用方法
    Apache Sentry部署
    Spark机器学习解析下集
  • 原文地址:https://www.cnblogs.com/java-le/p/14471517.html
Copyright © 2020-2023  润新知