单例模式.md

概念

单例模式(Singleton Design Pattern):一个类只允许创建一个对象(或者实例)


要解决的问题/用途

  • 资源访问冲突
  • 表示全局唯一类,如配置信息类连接池类ID生成器类

如何实现

实现方式 概念 是否线程安全 是否支持延迟加载 适用场景
饿汉式 单例实例在类加载的时候
instance静态实例就已经创建并初始化好了
详见代码
懒汉式 单例实例在第一次被使用时构建 可以加锁实现线程安全 详见代码
双重检测 只要instance被创建之后,即便再调用getInstance()函数也不会再进入到加锁逻辑中了。
所以,这种实现方式解决了懒汉式并发度低的问题
详见代码
静态内部类 java特有,在此不做讲解 - - -
枚举 java特有,在此不做讲解 - - -

1.饿汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package main
/*
饿汉模式适用场景:
如果初始化耗时长,那我们最好不要等到真正要用它的时候,
才去执行这个耗时长的初始化过程,这会影响到系统的性能
(比如,在响应客户端接口请求的时候,做这个初始化操作,
会导致此请求的响应时间变长,甚至超时)。
采用饿汉式实现方式,将耗时的初始化操作,
提前到程序启动的时候完成,这样就能避免在程序运行的时候,
再去初始化导致的性能问题。
如果实例占用资源多,按照fail-fast的设计原则(有问题及早暴露),
那我们也希望在程序启动时就将这个实例初始化好。
如果资源不够,就会在程序启动的时候触发报错(比如Java中的 PermGen Space OOM),
我们可以立即去修复。这样也能避免在程序运行一段时间后,
突然因为初始化这个实例占用资源过多,导致系统崩溃,影响系统的可用性。
*/
var es = &EagerSingleton{}

//func init() {
// 如果EagerSingleton有属性需要初始化,可以在init内进行
//}

func GetEsInstance() *EagerSingleton {
return es
}

type EagerSingleton struct {

}

2.懒汉式
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
package main

import "sync"

/*
懒汉模式适用场景:
懒汉式相对于饿汉式的优势是支持延迟加载。
*/

var lz *LazySingleton

type LazySingleton struct {
}

// 第一种:非线程安全
//func GetLzInstance() *LazySingleton {
// if lz == nil{
// lz = &LazySingleton{}
// }
// return lz
//}
//

// 第二种:加锁,并发性能最差

//var mu sync.Mutex

//func GetLzInstance() *LazySingleton {
// mu.Lock()
// defer mu.Unlock()
// if lz == nil {
// lz = &LazySingleton{}
// }
// return lz
//}

// 第三种:锁+双重检查,并发性较第二种稍好一点

//var mu sync.Mutex
//
//func GetLzInstance() *LazySingleton {
// if lz == nil {
// mu.Lock()
// defer mu.Unlock()
// if lz == nil {
// lz = &LazySingleton{}
// }
// }
// return lz
//}

// 第四种:懒汉式最优实现,通过golang特有的sync.Once来实现

var once sync.Once

func GetLzInstance() *LazySingleton {
once.Do(func() {
lz = &LazySingleton{}
})
return lz
}