😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

GOLANG ROADMAP

阅读模式

  • 沉浸
  • 自动
  • 日常
首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
author-avatar

GOLANG ROADMAP


首页
Go学习
  • Go学院

    • Go小课
    • Go视界
    • Go小考
    • Go实战
  • Go资源

    • 优质课程
    • 在线宝典
    • 资源下载
    • 帮找资源
训练营 🔥
  • Go体系课&实战训练营
  • 升值加薪陪跑训练营
Go求职
  • 求职刷题

    • 企业题库
    • 面试宝典
    • 求职面经
  • 求职服务

    • 内推互助
    • 求职助力
    • 内推公司
Go友会
  • 城市
  • 校园
推广返佣
  • 返佣排行
  • 返佣规则
  • 推广学院
实验区
  • Go周边
  • Go宝典

    • 推荐图书
    • 精品博文
  • Go开源

    • Go仓库
    • Go月刊
更多
  • 用户中心

    • 我的信息
    • 我的返佣
    • 我的消息
  • 玩转星球

    • 星球介绍
    • 星主权益
    • 吐槽专区
    • 成长记录
  • 合作交流

    • 商务合作
    • 讲师招募
    • 生态伙伴
  • Go真实面试题汇总系列

    • Go基础篇
  • 宝典内容

    • 76. runtime提供常见的方法
    • 90. golang支持哪些并发机制
    • 97. go并发机制
    • 101. go语言怎么做的连接复用,怎么支持的并发请求,go的netpoll是怎么实现的像阻塞read一样去使用底层的非阻塞read
    • 107. go用共享内存的方式实现并发如何保证安全?
    • 115. 讲一讲 Golang 的并发控制
    • 178. golang中Context的使用场景
    • 179. context 的数据结构
    • 190. Golang 怎么在并发编程中等待多个 goroutine 结束?
    • 275. schedulerc的实现细节
    • 283. 说一下reflect
    • 284. 有很多sync_recv状态是发生了什么
    • 302. go实现一个并发限制爬虫
    • 310. 两个协程交替打印一个数组,使数组中的数据按顺序输出
    • 313. 一组协程完成后需要通知其他协程,可以怎么办?
    • 317. 从运行速度来讲,go的并发模型channel和goroutine
    • 319. sync.Once如何实现线程安全
    • 326. go 同步、channel的实现
    • 333. golang怎么协调并发协程的调度
    • 337. 介绍一下 Go 的 context
    • 352. 如何实现只开100个协程
    • 365. 有生产者和消费者应该在哪里关闭通道?
    • 381. golang除了goroutine还有什么处理并发的方法
    • 384. 给定n个并发量,并发处理数组
    • 404. context上下文控制
    • 409. go 多协程怎么同步
    • 413. go 怎么控制查询timeout (context)
    • 419. 怎么理解“不要用共享内存来通信,而是用通信来共享内存”
    • 439. Context 包的实现
    • 445. 协程间通信
    • 450. 写个channel相关的题,并发模型,爬虫url,控制并发量
    • 457. Go 并发优秀在哪里,需要通过实际的测试,benchmark等说明
    • 462. Go 高并发的特点
    • 469. go waitgroup 的坑

😥 整理不易,此资源只针对正式星主开放,
还请入驻星球后再来观看。

319. sync.Once如何实现线程安全


企业题库解析小组

题目序号:(478) 题目来源: 滴滴 频次: 1

答案:阿纪、

  1. sync.Once源码分析 sync.Once是通过一个对象实现的.

    type Once struct {
        done unit32
        m Mutex
    }
    
    1
    2
    3
    4

    他们分别为标记是否已经执行过的标志(done),以及执行时所用的互斥锁(m) 除了结构体外,sync.Once还包括了一个公开的方法Do:

    func (o *Once) Do(f func()) {
        if atomic.LoadUint32(&o.done) == 0 {
            o.doSlow(f)
        }
    }
    
    1
    2
    3
    4
    5

    Once.Do方法的实现非常简单,通过atomic.LoadUint32获取Once实例的done属性值。 若done值为0时,表示函数f未被调用过或正运行中且未结束,则将调用doSlow方法; 若done值为1时,表示函数f已经调用且完成,则直接返回。 这里使用了原子操作方法atomic.LoadUint32而不是直接将o.done进行比较,也是为了避免并发状态下错误地判断执行状态,产生不必要的锁操作带来的时间开销。

    func (o *Once) doSlow(f func()) {
        o.m.Lock()
        defer o.m.Unlock()
        if o.done == 0 {
            defer atomic.StoreUint32(&o.done, 1)
            f()
        }
    }
    
    1
    2
    3
    4
    5
    6
    7
    8

    Once.doSlow方法的实现使用了传统的互斥锁Mutex操作,在执行时即调用o.m.Lock方法获得锁,然后再继续判断是否已经完成并调用f函数。 可以看到,在获得锁后还需要对o.done的值进行一次判断,避免了f函数被重复调用。 最后,在退出doSlow方法时还需要对获取的锁进行释放,若进入到f函数的调用则需要更改o.done属性值。