Golang 单例模式

单例模式是最简单的设计模式之一,这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

意图: 保证一个类型仅有一个实例,并提供一个访问它的全局访问点。
主要解决: 一个全局使用的类型频繁地创建与销毁。
何时使用: 当您想控制实例数目,节省系统资源的时候。
如何解决: 判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

实现

Golang 目前常见的有以下四种方式(懒汉式、 饿汉式、 双重检查、 sync.Once)

懒汉式

非线程安全

package main

import (
"fmt"
"unsafe"
)

type SingletonInstance struct {
value int
}

var singletonInstance *SingletonInstance

func 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 SingletonInstance

func 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 sync

import (
"sync/atomic"
)

// Once is an object that will perform exactly one action.
type Once struct {
done uint32
m Mutex
}

func (o *Once) Do(f func()) {
// o.done 初始化为0,双重检查
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 {
// o.done 赋值为1,atomic 原子操作
defer atomic.StoreUint32(&o.done, 1)
// 执行函数
f()
}
}

参考资料