初识golang

初识golang

单例模式是设计模式里最为常用的一种,应用该设计模式的目的是保证类仅有一个全局的对象实例。

懒汉模式(Lazy Loading)

懒汉模式是最为简单常见的,最大的缺点是非线程安全的。

type singleton struct {
    //...
}
//private
var instance *singleton
//public
func GetInstance() *singleton {
    if instance == nil {
        instance = &singleton{}
    }
    return instance
}

带锁的单例模式

sync包提供两种锁类型:Mutex和RWMutex。Mutex是我们常见的锁类型,当一个goroutine获得Mutex之后,其它的goroutine只能进行等待直到该Mutex被释放。而RWMutex则是较为友好的单读多写模型,写锁会阻止其它所任何goroutine访问,而读锁则只会阻止写而不阻止读。

这里使用了Go的sync.Mutex,解决了懒汉模式的线程安全问题,但是在已生成实例后每次访问还都会调用锁,造成不必要的开销。

type singleton sturct {
}

var instance *singleton
var mu sync.Mutex

func GetInstance() *singleton {
    mu.Lock()
    defer mu.Unlock()

    if instance == nil {
        instance = &singleton{}
    }
    return instance
}
大专栏  初识golange>

带检查锁的单例模式

通过再封加一层判断,可以解决不必要开销的问题。

if instance == nil {
    mu.Lock()
    defer mu.Unlock()

    if instance == nil {
        instance = &singleton{}
    }
    return instance
}

通过sync/atomic包中的原子操作,还可以写成

import "sync"
import "sync/atomic"

var initialized uint32
...
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
}

sync.Once

Go语言中提供了一个sync.Once类型解决全局唯一性操作问题,Once.Do()方法可以保证全局范围内只调用指定的函数一次,而且其他goroutine调用到该语句时都将被阻塞,直到全局唯一的Once.Do()被调用后才执行。

import "sync"

type singleton struct {
}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
    once.Do(func() {
        instance = &singleton{}
    })
    return instance
}