package main
import (
"fmt"
"sync"
"time"
)
func main() {
// 演示懒汉式
go func() {
s := NewLazySingleton()
s.Say()
}()
singleton := NewLazySingleton()
singleton.Say()
// 演示饿汉式
go func() {
h := NewHungrySingleton()
h.Say()
}()
hungry := NewHungrySingleton()
hungry.Say()
time.Sleep(time.Second)
}
// 定义一个结构体(至关于面向对象语言里面的class)
type Singleton struct {
name string
}
// 至关于class的方法
func (s Singleton) Say() {
fmt.Printf("%s: Say Hello\n", s.name)
}
// 因为Go并非彻底面向对象的语言,只能经过包级别的全局变量模拟类变量
var lazyInstance *Singleton
// 为了Go协程并发安全,能够加锁,若是不加锁第一次实例化的时候会出现data race操做,可是其实并不影响功能
// 第一加锁方式是使用mutex
// mu.lock
// defer mu.unlock
// 可是这样并不优雅,至关于每次New的时候都得加锁,影响性能,因此最好的方式是使用once
var once sync.Once
// 懒汉式,所谓懒汉式就是比较懒,等你第一次调用的时候才会去实例化对象
func NewLazySingleton() *Singleton {
once.Do(func() {
fmt.Println("init lazy")
lazyInstance = &Singleton{name: "lazy"}
})
return lazyInstance
}
var hungryInstance = Singleton{name: "hungry"}
// 饿汉式,所谓饿汉式就是在你调用New以前就已经初始化好了,这个更简单,并且也不须要锁
func NewHungrySingleton() *Singleton {
return &hungryInstance
}
复制代码
单例模式在实际开发中用的仍是比较的多,好比数据库链接池、配置文件等数据库