单例模式(Singleton Pattern)

单例模式可以说是最容易理解的一种设计模式了,当需要某个类仅有一个全局唯一对象时可以使用,比如某些配置项。核心思想就是新建某个类实例时先进行一次判断,如果不存在则创建新实例返回,否则返回已经存在的实例。

懒汉模式(Lazy Loading)

很常见的一种方式,不过并非是线程安全的:

1
2
3
4
5
6
7
8
9
type singleton struct {
}
var instance *singleton
func GetInstance() *singleton {
if instance == nil {
instance = &singleton{}
}
return instance
}

带单锁的单例模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import "sync"

type singleton struct {
}

var instance *singleton
var mu sync.Mutex

func GetInstance() *singleton {
mu.Lock()
defer mu.Unlock()

if instance == nil {
instance = &singleton{}
}
return instance
}

解决线程安全问题,很容易想到的就是加锁。这种方式有个缺点就是每次获取实例时候都要对锁进行操作,会降低性能。

双重锁定

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
package main

import (
"fmt"
"sync"
"sync/atomic"
)

type singleton struct {
}

var instance *singleton
var mu sync.Mutex

var initialized uint32

func GetInstance() *singleton {

if atomic.LoadUint32(&initialized) == 1 {
return instance
}
mu.Lock()
defer mu.Unlock()

if instance == nil {
instance = &singleton{}
atomic.StoreUint32(&initialized, 1)
}
return instance
}

这里使用atomic来保证原子操作。不过代码还可以更精简,使用golang中的Once

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import (
"fmt"
"sync"
)

type singleton struct {
}

var instance *singleton
var once sync.Once

func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}