golang 中的 单例模式
单例模式(singleton),保证一个类只有一个实例,并提供一个访问它的全局访问点。
为什么要确保一个类只有一个实例?
比如我们的APP中有一个类用来保存运行时全局的一些状态信息(如:mysql 连接),整个程序只需要一个 mysql 连接实例就可以了。
Go 语言实现单例模式的有两种方式,分别是懒汉式、饿汉式。不管那种模式最终目的只有一个,就是只实例化一次,只允许一个实例存在。
1. 懒汉式
懒汉模式,即在使用对象实例时,才去创建,不会提前创建。避免饿汉模式的空间浪费。
1.1 非线程安全(不加锁),它不能在多线程情况下使用
type singleton struct {} // private var instance *singleton // public func GetInstance() *singleton { if instance == nil { instance = &singleton{} // not thread safe } return instance }
1.2 整个方法加锁
这里对整个方法进行了加锁,这种可以解决并发安全的问题,但是效率就会降下来,
type singleton struct {} var instance *singleton var mu sync.Mutex func GetInstance() *singleton { mu.Lock() defer mu.Unlock() if instance == nil { instance = &singleton{} // unnecessary locking if instance already created } return instance }
1.3 双重检查锁(Check-Lock-Check 机制)
只有当对象未初始化的时候,才会有加锁和减锁的操作。
type singleton struct {} var instance *singleton var lock sync.Mutex func GetInstance() *singleton { if instance == nil{ lock.Lock() if instance == nil{ instance = new(singleton) } lock.Unlock() } return instance }
1.4 sync.Once 原子操作实现(推荐)
原理也是 Check-Lock-Check 机制,既然标准包已经定义,那就直接使用吧,最安全有效又简洁的方法
package singleton import ( "sync" ) type singleton struct {} var instance *singleton var once sync.Once func GetInstance() *singleton { once.Do(func() { instance = &singleton{} }) return instance }
2. 饿汉式
饿汉模式,在程序加载阶段 init() 创建对象实例或者定义一个全局变量的方式,虽然保证线程安全,但是会减慢程序启动速度。如果对象实例不被调用,则会浪费一段内存空间。
2.1 全局变量方式
type singleton struct {} var instance = new(singleton) func GetInstance() *singleton{ return instance }
2.2 init 方式
type singleton struct {} var instance *singleton func init() { instance = new(singleton) } func GetInstance() *singleton{ return instance }
3.注意点
除了 GetInstance 方法 外其他类型名等 都使用的小写字母开头,避免其他包直接调用。
共 0 条评论