Go 并发实战 -- sync Once

作者: 邹志全 | 来源:发表于2019-07-10 22:52 被阅读8次

前言

Once是一个非常实用的API,它保证了一个事情仅做一次,这个在许多场景非常有用,所以Once也是go提供的为数不多的API之一。

语法基础

Once的语法非常简单,整个API就提供了一个Do函数,Do函数接受的是一个函数对象,通过once.Do可以保证这个事情仅做一次,来看一个demo:

func main() {
    var once = sync.Once{}
    once.Do(say)
    once.Do(say)
    once.Do(say)
    once.Do(say)
}

func say() {
    fmt.Println("say once")
}

输出:


image.png

源码实现

// Once is an object that will perform exactly one action.

type Once struct {
    m    Mutex // 一把锁
    done uint32 // 是否已经做过的标记
}

func (o *Once) Do(f func()) {
// 如果已经做过了直接返回,这里使用atmoic保证并发场景下的安全性
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
// 这里有一个先判断后操作的竞态条件,所以锁了一下
    o.m.Lock()
    defer o.m.Unlock()
    if o.done == 0 {
        // 将状态标记为已完成,这个过程还是在锁内部
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

ps:源码中有一个细节点,如果声明了多个defer,按照定义顺序,倒序执行,这也就是为什么最终把状态置为已完成是发生在锁内部了。
关于Once的内容挺简单的,暂时先介绍这么多。

相关文章

  • Go 并发实战 -- sync Once

    前言 Once是一个非常实用的API,它保证了一个事情仅做一次,这个在许多场景非常有用,所以Once也是go提供的...

  • golang 系列:sync.Once 讲解

    sync.Once 介绍 之前提到过 Go 的并发辅助对象:WaitGroup[https://mp.weixin...

  • once.go

    概述 sync包中的once.go可以在并发情况下保证自定义方法仅仅被执行一次 原型 Once Struct Do...

  • Go 并发实战 -- sync WaitGroup

    前言 waitgroup也是一个非常有用的并发工具,有点像是Java中的CyclicBarrier,只不过Go中的...

  • Go 并发实战 -- sync Cond

    前言 go中的sync.Cond也就是condition,是一个条件同步变量,与Java中Object的wait、...

  • Go 并发实战 -- sync Mutex

    前言 在并发编程中我们可以使用channel来协同各个goroutine,但是很多场景我们也是需要使用sync的比...

  • Go 并发实战 -- sync RWMutex

    前言 sync中包含Mutex、RWMutex两个排他锁,上一篇介绍了最基础的Mutex锁,本篇来说一下基于Mut...

  • Go 并发实战 -- sync Pool

    前言 sync包中最后一个要说的API是sync.Pool,本质上来说Pool应该不算是sync并发相关的内容,但...

  • Go 并发实战 -- sync Map

    前言 Java中线程安全的map主要有HashTable、ConcurrentHashMap,go中线程安全的Ma...

  • go单例模式之懒汉模式

    可以通过sync包中的sync.Once实现单例模式。 如下是once.go中的Do()方法的源码: 下面是用sy...

网友评论

    本文标题:Go 并发实战 -- sync Once

    本文链接:https://www.haomeiwen.com/subject/bodhkctx.html