一个类只允许创建一个对象,那么这个类就叫做一个单例类,这种设计模式就叫做单例设计模式。单例模式不仅有利于减少内存开支,还有减少系统性能开销、防止多个实例产生冲突等优点。
因为单例模式保证了实例的全局唯一性,而且只被初始化一次,所以比较适合全局共享一个实例,且只需要被初始化一次的场景
例如数据库实例、全局配置、全局任务池
要求生成唯一的序列号
缓存之类的数据,可以用单例缓存起来
创建一个对象需要消耗过多的资源时,比如文I/O与数据的连接等等
单例模式又分为饿汉方式和懒汉方式。饿汉方式指全局的单例实例在包被加载时创建,而懒汉方式指全局的单例实例在第一次被使用时创建,我们可以看到,这种命名方式非常形象地体现了它们不同的特点。
饿汉式:
package main
import "fmt"
// Singleton 保证一个类永远只能有一个对象,这个对象还能被系统的其他模块使用
type singleton struct{}
var instance *singleton = &singleton{}
func GetInstance() *singleton {
return instance
}
func (s *singleton) SomeTing() {
fmt.Println("单例中的某方法")
}
懒汉式:
懒汉式在平时使用比较多,但是在并发环境中他是不安全的,需要进行加锁
package main
import (
"fmt"
"sync"
"sync/atomic"
)
// Singleton 保证一个类永远只能有一个对象,这个对象还能被系统的其他模块使用
type singleton struct{}
var instance *singleton
// 定义一个锁
var lock sync.Mutex
// 定义一个标记
var initialized uint32
func GetInstance() *singleton {
if atomic.LoadUint32(&initialized) == 1 {
return instance
}
lock.Lock()
defer lock.Unlock()
//只有首次GetInstance()方法被调用,才会生成这个单例的对象
if instance == nil {
instance = &singleton{}
atomic.StoreUint32(&initialized, 1)
return instance
}
return instance
}
func (s *singleton) SomeTing() {
fmt.Println("单例中的某方法")
}
除了懒汉式和饿汉式以外,在golang语言中有一种更加优雅的方法实现单例模式,使用once.Do可以确保 instance 实例全局只被创建一次,once.Do 函数还可以确保当同时有多个创建动作时,只有一个创建动作在被执行
package main
import "sync"
var once sync.Once
type singleton struct{}
var instance *singleton
func GetInstance() *singleton {
//使用once.Do
once.Do(func() {
instance = &singleton{}
})
return instance
}