go设计模式之单例模式

260 阅读1分钟

单例模式在系统设计中很常用,如数据库的连接对象等,该类只有一个实例存在,实现很简单,就是在创建实例时,判断一下,实例是否已经存在。

以下使用go语言实现单例模式

package main

import "fmt"

type Manager struct {
	id int
}

func (m *Manager) Print() {
	fmt.Println("我是独有的", m.id)
}

var m *Manager

func GetInstance() *Manager {
	if m == nil {
  	m = &Manager{
  		id: 123,
	}
  }
  return m
}

func main() {
	manger :=GetInstance()
	manger.Print()
}

以上,我们实现了一个简单的单例,但存在一个问题,在并发场景下,如果线程1获取到 m =nil,执行创建,线程2也获取到m =nil,也会执行实例创建,为了防止该问题出现,需要通过锁机制来解决该问题。在go语言下,有一个sync的包,他有一个对象once,有一个方法Do,内部实现了锁机制

再来看一下改进后的实现

package main

import (
	"fmt"
	"sync"
)

type Manager struct {
	id int
}

func (m *Manager) Print() {
	fmt.Println("我是独有的", m.id)
}

var m *Manager
var once sync.Once

func GetInstance() *Manager {
	once.Do(func (){
		m = &Manager{
			id: 123,
		}
	})
    return m
}

func main() {
	manger :=GetInstance()
	manger.Print()
}

以上实现了一个单例的demo, 看一下Do的方法

func (o *Once) Do(f func()) {
	if atomic.LoadUint32(&o.done) == 1 {
		return
	}
	// Slow-path.
	o.m.Lock()
	defer o.m.Unlock()
	if o.done == 0 {
		defer atomic.StoreUint32(&o.done, 1)
		f()
	}
}