设计模式go语言实现----单例模式Singleton

1 单例模式定义

保证一个类仅有一个实例,并提供一个访问它的全局访问点

设计模式go语言实现----单例模式Singleton_第1张图片

使用单例模式需要注意三个要点:

  • 某个类只能有一个实例
  • 这个类必须自行创建这个实例
  • 这个类必须自行向整个系统提供这个实例

单例模式写法:

  • 饿汉式:类在*编译时*创建自己的实例
  • 懒汉式:类在*运行时*创建自己的实例

依据以上,读者可以自行辨别下面的代码属于哪种写法

2 单例模式的gol语言实现

2.1 不考虑并发情况

package manager
import (
	"fmt"
)

var m *Manager

func GetInstance() *Manager {
	if m == nil {
		m = &Manager{}
	}
	return m
}

type Manager struct {
}

func (p Manager) Manage() {
	fmt.Println("manage...")
}

以上代码虽然实现了单例模式,在非并发的环境下执行,确实没有问题,但是考虑并发的情况,当第一个goroutine执行到m=&Manager{}之前,第二个gotoutine也来获取实例了,第二个gotoutine去判断m是不是等于nil,因为m=&Manager{}还没来得及执行,所以m=nil,那么if中的m = &Manager{}就可能会被执行两遍。
利用go的锁机制sync.Mutex修改以上代码。

2.2 考虑并发的情况

package manager
import (
	"fmt"
	"sync"
)

var m *Manager
var lock *sync.Mutex = &sync.Mutex{}

func GetInstance() *Manager {
	lock.Lock()
	defer lock.Unlock()
	if m == nil {
		m = &Manager{}
	}
	return m
}

type Manager struct {
}

func (p Manager) Manage() {
	fmt.Println("manage...")
}

这样修改之后,保证只有一个goroutine能够执行GetInstance函数,这样并发的问题就解决了,但是现在又有一个问题,每次goroutine来的时候都会被锁挡在GetInstance之外等上一个goroutine执行结束,这样代码执行效率肯定会下降,下面我们引入双重锁机制类修改我们的代码。

package manager
import (
	"fmt"
	"sync"
)

var m *Manager
var lock *sync.Mutex = &sync.Mutex{}

func GetInstance() *Manager {
	if m == nil {
		lock.Lock()
		defer lock.Unlock()
		if m == nil {
			m = &Manager{}
		}
	}
	return m
}

type Manager struct {
}

func (p Manager) Manage() {
	fmt.Println("manage...")
}

这样的话就避免了每次gouroutine过来的时候都需要加锁了。有的读者可能会问,为什么我们的代码里面需要执行两次m==nil的判断呢?试想一下当两个goroutine同时通过第一重m==nil判断的时候,由于锁机制,只有一个goroutine继续执行,另一个则在外排队等待,当第一个goroutine执行完毕之后,如果没有第二重m==nil判断的话,第二个goroutine也会继续执行语句m = &Manager{},这样就没有起到单例的目的了。
其实go语言中有一种机制可以保证代码只会被执行一次,而不需要我们手动加锁解锁,也就是go中的sync.Once,它的Do方法会保证传给它的函数只会被调用一次。

2.3 使用sync.Once改进

package manager
import (
	"fmt"
	"sync"
)

var m *Manager
var once sync.Once

func GetInstance() *Manager {
	once.Do(func() {
		m = &Manager{}
	})
	return m
}

type Manager struct {
}

func (p Manager) Manage() {
	fmt.Println("manage...")
}

有没有发现go代码很优雅的就实现了单例模式呢?

参考资料:
[1] 单例模式
[2] Go设计模式之单例模式
[3] 设计模式-单例模式(Go语言描述)

你可能感兴趣的:(设计模式,go,设计模式之go语言实现)