kevinyan815 / gocookbook

go cook book
MIT License
789 stars 167 forks source link

Go 中使用单例模式 #83

Open kevinyan815 opened 2 years ago

kevinyan815 commented 2 years ago

单例模式,分两种加载模式,下面介绍下 Go 里面怎么使用单例模式。

饿汉模式

适合程序初始化时就确定怎么加载实例的情况

package singleton

// Singleton 饿汉式单例
type Singleton struct{}

var singleton *Singleton

func init() {
    singleton = &Singleton{}
}

// GetInstance 获取实例
func GetInstance() *Singleton {
    return singleton
}

懒汉模式

延迟加载,适合根据传入参数实现定制化的初始化操作。

package singleton

import (
    "sync"
    "sync/atomic"
)

type singleton struct {}

var (
    initialized uint32
    instance *singleton
    mu sync.Mutex
)

func GetInstance() *singleton {

    if atomic.LoadUint32(&initialized) == 1 { // 原子操作
        return instance
    }

    mu.Lock()
    defer mu.Unlock()

    if initialized == 0 {
        instance = &singleton{}
        atomic.StoreUint32(&initialized, 1)
    }

    return instance
}

上面通过了atomic 和 mutex 进行双重检查,保证线程安全,不过可以利用 sync.Once 实现更简洁的版本,这一版最好也记住,有可能面试的时候就不让你用sync.Once实现,sync.Once 内部也是维护了个标志为,用atomic 判断它是否已经执行过函数

Java 里的线程安全的单例也是这么通过volatile+synchronized 双锁检查实现的。

简洁版的懒汉模式单例

package singleton

type singleton struct {}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}

这里直接上的代码,没有什么废话,如果想看故事版的,可以访问最简单的单例模式,Go版本的实现你写对了吗?