单例模式
单例模式规定,一个类只能实例化一个实例。因此单例模的特点是:
- 只有一个实例
- 必须自行创建
- 必须自行向系统提供这个实例
应用场景
单例模式的主要使用场景有以下两个方面:
- 资源共享情况下避免资源操作导致的性能损耗,比如日志管理器,web网站计数器,应用配置管理对象等
- 方便对资源的控制,比如线程池和数据库连接池等
golang单例模式的实现方式
饿汉模式
直接创建好对象,这样不需要判断为空,同时也是线程安全。唯一的缺点是在导入包的同时会创建该对象,并持续占有在内存中。
var instance Tool
func GetInstance() *Tool {
return &instance
}
懒汉模式
对象只有在调用GetInstance方法的时候才会实例化,节省资源。
golang 中懒汉模式可以有多种实现方式,本文用sync.once函数实现。
singleton.go :
package singleton
import "sync"
//定义包私有结构体
type singleton struct {
name string
}
var mysingleton *singleton
var once sync.Once
func Getinstance() *singleton {
//调用once.Do函数,进行实例化
once.Do(func() {
mysingleton=&singleton{}
})
return mysingleton
}
singleton_test.go :
package singleton
import (
"log"
"sync"
"testing"
)
var w sync.WaitGroup
func TestSintonsample(t *testing.T) {
s1:=Getinstance()
s2:=Getinstance()
if s1==s2{
log.Printf("s1 的地址是 %p,s2 的地址是 %p",s1,s2)
log.Println("s1 和 s2 是相同的实例")
}
}
func TestConcurrencesingleton (t *testing.T) {
//设置100个goroutine,并发的实例化这个struct,对比每个实例是否相同
singlelist:=make([]*singleton,0)
for i:=0;i<100;i++{
w.Add(1)
go func(group sync.WaitGroup) {
defer w.Done()
singlelist=append(singlelist,Getinstance())
}(w)
}
w.Wait()
for i:=0;i<len(singlelist)-1;i++{
if singlelist[i]!=singlelist[i+1]{
t.Fatal("instance is not equal")
}
}
}
在目录下执行go test,可自动执行Test开头的测试函数,通过结果对比可以发现,单例模式实例化的对象的地址都是一样的。
2020/09/27 16:29:28 s1 的地址是 0xc00003e490,s2 的地址是 0xc00003e490
2020/09/27 16:29:28 s1 和 s2 是相同的实例
2020/09/27 16:29:28 s1 is 0xc00003e4b0,s2 is 0xc00003e4c0
PASS
ok designpatten.com/singleton 3.342s
有疑问加站长微信联系(非本文作者)