“保证一个类仅有一个实例,并提供一个访问他的全局访问点”—这是对单例模式最简单的定义;
代码实现
- 不考虑并发的单例模式
// Singleton project main.go
package main
import (
"fmt"
)
var m *Manager
func GetInstance(name string) *Manager {
if m == nil {
m = &Manager{name: name}
}
return m
}
type Manager struct {
name string
}
func (this *Manager) say_name() {
fmt.Println(this.name)
}
func main() {
man1, man2 := GetInstance("hello"), GetInstance("world")
man1.say_name()
man2.say_name()
}
2.并发情况下的单例模式
并发情况下,上面的代码并不能保证只创建一个实例(当在并发的情况下,当第一个goroutine执行到m = &Manager{name: name}之前,第二个goroutine也正好获取实例,此时判断m是否为空,因为m = &Manager{name: name}还未执行,m为非空,这时候代码就要执行了两次),为了解决这个问题,我们引入go的锁机制。
// Singleton project main.go
package main
import (
"fmt"
"sync"
)
var m *Manager
var lock *sync.Mutex = &sync.Mutex{}
func GetInstance(name string) *Manager {
if m == nil {
lock.Lock()
defer lock.Unlock()
if m == nil {
m = &Manager{name: name}
}
}
return m
}
type Manager struct {
name string
}
func (this *Manager) say_name() {
fmt.Println(this.name)
}
func main() {
man1, man2 := GetInstance("hello"), GetInstance("world")
man1.say_name()
man2.say_name()
}
3.go专属的单例模式
因为单例模式之创建一个实例,go中sync.Once中有个Do方法,可以保证代码只被执行一次!!!
package main
import (
"fmt"
"sync"
)
var m *Manager
var once sync.Once
func GetInstance(name string) *Manager {
once.Do(func() {
m = &Manager{name: name}
})
return m
}
type Manager struct {
name string
}
func (this *Manager) say_name() {
fmt.Println(this.name)
}
func main() {
man1, man2 := GetInstance("hello"), GetInstance("world")
man1.say_name()
man2.say_name()
}