单例模式
- 确保任何状况下一个类只有一个实例
通常而言, 单例实例会在构造体首次初始化时创立。 为了实现这一操作, 咱们在构造体中定义一个 getInstance
获取实例办法。 该办法将负责创立和返回单例实例。 创立后, 每次调用 getInstance
时都会返回雷同的单例实例。
协程方面又有什么须要留神的吗? 每当多个协程想要拜访实例时, 单例构造体就必须返回雷同的实例。 正因如此, 单例设计模式的施行工作很容易出错。
饿汉模式
在初始阶段创立实例而不是在应用时创立实例。不须要加锁,更平安;然而当程序中不应用该实例会节约空间,减慢启动速度。
// 应用全局变量type single struct {}var instance = new(single)func GetInstance() *single{ return instance}// init函数创立实例// 咱们能够在 init函数中创立单例实例。 这仅实用于实例的晚期初始化工作曾经确定时。init函数仅会在包中的每个文件里调用一次, 所以咱们能够确定其只会创立一个实例。type single struct {}var instance *singlefunc init() { instance = new(single)}func GetInstance() *single{ return instance}
懒汉模式
sync.Once举荐应用
package mainimport ( "fmt" "sync")var once sync.Oncetype single struct {}var singleInstance *singlefunc getInstance() *single { if singleInstance == nil { once.Do( func() { fmt.Println("Creating single instance now.") singleInstance = &single{} }) } else { fmt.Println("Single instance already created.") } return singleInstance}func main() { for i := 0; i < 30; i++ { go getInstance() } // Scanln is similar to Scan, but stops scanning at a newline and // after the final item there must be a newline or EOF. fmt.Scanln()}
双重检测
- 最开始时会有
nil
查看, 确保singleInstance
单例实例在最开始时为空。 这是为了避免在每次调用getInstance
办法时都去执行耗费微小的锁定操作。 如果查看不通过, 则就意味着singleInstance
字段已被填充。 singleInstance
构造体将在锁定期间创立。- 在获取到锁后还会有另一个
nil
查看。 这是为了确保即使是有多个协程绕过了第一次查看, 也只能有一个能够创立单例实例。 否则, 所有协程都会创立本人的单例构造体实例。
package mainimport ( "fmt" "sync")var lock = &sync.Mutex{}type single struct {}var singleInstance *singlefunc getInstance() *single { if singleInstance == nil { lock.Lock() defer lock.Unlock() if singleInstance == nil { fmt.Println("Creating single instance now.") singleInstance = &single{} } else { fmt.Println("Single instance already created.") } } else { fmt.Println("Single instance already created.") } return singleInstance}func main() { for i := 0; i < 30; i++ { go getInstance() } // Scanln is similar to Scan, but stops scanning at a newline and // after the final item there must be a newline or EOF. fmt.Scanln()}