sync.Once

2年前 (2022) 程序员胖胖胖虎阿
236 0 0

Once

Once 可以用来执行且仅仅执行一次动作,常常用于单例对象的初始化场景。

once可用于实现单例模式中懒汉实现:

package main

import (
    "fmt"
    "sync"
)

var once sync.Once

type single struct {
}

var singleInstance *single

func getInstance() *single {
    if singleInstance == nil {
        once.Do(
            func() {
                fmt.Println("Creating single instance now.")
                singleInstance = &single{}
            })
    } else {
        fmt.Println("Single instance already created.")
    }

    return singleInstance
}

func main() {

    for i := 0; i < 30; i++ {
        go getInstance()
    }

    // Scanln is similar to Scan, but stops scanning at a newline and
    // after the final item there must be a newline or EOF.
    fmt.Scanln()
}

Once结构体

type Once struct {
    done uint32        // done 指示操作是否已执行
    m    Mutex
}

Do

func (o *Once) Do(f func())

sync.Once 只暴露了一个方法 Do,你可以多次调用 Do 方法,但是只有第一次调用 Do
方法时 f 参数才会执行,这里的 f 是一个无参数无返回值的函数。因为当且仅当第一次调用 Do 方法的时候参数 f 才会执行,即使第二次、第三次、第 n 次调用时 f 参数的值不一样,也不会被执行。

func (o *Once) Do(f func()) {
    if atomic.LoadUint32(&o.done) == 0 {
        // Outlined slow-path to allow inlining of the fast-path.
        o.doSlow(f)
    }
}

func (o *Once) doSlow(f func()) {
    o.m.Lock()
    defer o.m.Unlock()
    // 双重检测
    // 保证了并发的 goroutine 会等待 f 完成,而且还不会多次执行 f。
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}
版权声明:程序员胖胖胖虎阿 发表于 2022年9月27日 下午5:08。
转载请注明:sync.Once | 胖虎的工具箱-编程导航

相关文章

暂无评论

暂无评论...