单例模式是最简单的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
意图: 保证一个类型仅有一个实例,并提供一个访问它的全局访问点。主要解决: 一个全局使用的类型频繁地创建与销毁。何时使用: 当您想控制实例数目,节省系统资源的时候。如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建。
实现 Golang 目前常见的有以下四种方式(懒汉式、 饿汉式、 双重检查、 sync.Once)
懒汉式 非线程安全 package mainimport ( "fmt" "unsafe" ) type SingletonInstance struct { value int } var singletonInstance *SingletonInstancefunc GetSingletonInstance () *SingletonInstance { if singletonInstance == nil { singletonInstance = new (SingletonInstance) } return singletonInstance } func main () { s := GetSingletonInstance() b := GetSingletonInstance() c := new (SingletonInstance) fmt.Println(unsafe.Pointer(s)) fmt.Println(unsafe.Pointer(b)) fmt.Println(unsafe.Pointer(c)) }
线程安全 利用 sync.Mutex
进行加锁,保证线程安全。缺点: 加锁有了额外开销。
type SingletonInstance struct { value int } var ( lock sync.Mutex singletonInstance *SingletonInstance ) func GetSingletonInstance () *SingletonInstance { lock.Lock() defer lock.Unlock() if singletonInstance == nil { singletonInstance = new (SingletonInstance) } return singletonInstance }
饿汉式 导入包的时候直接创建实例,这样无需判空且线程安全。优点: 简单方便缺点: 不管程序中是否使用都会生成该实例,该实例持续占有在内存中适用场景: 该实例使用频繁,功能简单占用内存少
type SingletonInstance struct { value int } var singletonInstance SingletonInstancefunc GetSingletonInstance () *SingletonInstance { return &singletonInstance }
双重检查 第一次判断不加锁,第二次加锁保证线程安全,实例创建完成后,获取实例就不用加锁了。
type SingletonInstance struct { value int } var ( lock sync.Mutex singletonInstance *SingletonInstance ) func GetSingletonInstance () *SingletonInstance { if singletonInstance == nil { lock.Lock() if singletonInstance == nil { singletonInstance = new (SingletonInstance) } lock.Unlock() } return singletonInstance }
sync.Once sync.Once
确保创建实例子的函数只执行一次
type SingletonInstance struct { value int } var ( one sync.Once singletonInstance *SingletonInstance ) func GetSingletonInstance () *SingletonInstance { one.Do(func () { singletonInstance = new (SingletonInstance) }) return singletonInstance }
sync.Once 源码分析 package syncimport ( "sync/atomic" ) type Once struct { done uint32 m Mutex } func (o *Once) Do (f func () ) { if atomic.LoadUint32(&o.done) == 0 { o.doSlow(f) } } func (o *Once) doSlow (f func () ) { o.m.Lock() defer o.m.Unlock() if o.done == 0 { defer atomic.StoreUint32(&o.done, 1 ) f() } }
参考资料