Open kevinyan815 opened 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版本的实现你写对了吗?
单例模式,分两种加载模式,下面介绍下 Go 里面怎么使用单例模式。
饿汉模式
适合程序初始化时就确定怎么加载实例的情况
懒汉模式
延迟加载,适合根据传入参数实现定制化的初始化操作。
上面通过了atomic 和 mutex 进行双重检查,保证线程安全,不过可以利用 sync.Once 实现更简洁的版本,这一版最好也记住,有可能面试的时候就不让你用sync.Once实现,sync.Once 内部也是维护了个标志为,用atomic 判断它是否已经执行过函数。
Java 里的线程安全的单例也是这么通过volatile+synchronized 双锁检查实现的。
简洁版的懒汉模式单例
这里直接上的代码,没有什么废话,如果想看故事版的,可以访问最简单的单例模式,Go版本的实现你写对了吗?