Go设计模式之Singleton

分享到:

Overview


Singleton - 单例模式

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

实现

饿汉式

饿汉式单例是指在方法调用前,实例就已经创建好了。

按照用法使用,可以看到控制台输出10次单例的内存地址是一样的。

 1package main
 2
 3import (
 4	"fmt"
 5	"sync"
 6	"time"
 7)
 8
 9type (
10	server struct {
11		port int
12	}
13)
14
15var (
16	instance = &server{}
17)
18
19func getServerSingleton() *server {
20	return instance
21}
22
23/*
24server ptr: 0x1182ec0
25server ptr: 0x1182ec0
26server ptr: 0x1182ec0
27server ptr: 0x1182ec0
28server ptr: 0x1182ec0
29server ptr: 0x1182ec0
30server ptr: 0x1182ec0
31server ptr: 0x1182ec0
32server ptr: 0x1182ec0
33server ptr: 0x1182ec0
34*/

懒汉式 - 非Goroutine安全

懒汉式单例是指在方法调用获取实例时才创建实例,因为相对饿汉式显得“不急迫”,所以被叫做“懒汉模式”。

按照用法使用,可以看到控制台输出10次单例的内存地址并不完全一样。

一共有以下3个指针:

  • 0xc0000c4000
  • 0xc0000ca000
  • 0xc0000c2000

可见此懒汉模式不支持在实例未初始化时高并发调用。

 1package main
 2
 3type (
 4	server struct {
 5		port int
 6	}
 7)
 8
 9var (
10	instance *server
11)
12
13func getServerSingleton() *server {
14	if instance == nil {
15		instance = &server{}
16	}
17
18	return instance
19}
20
21/*
22server ptr: 0xc0000c4000
23server ptr: 0xc0000ca000
24server ptr: 0xc0000c4000
25server ptr: 0xc0000c2000
26server ptr: 0xc0000c2000
27server ptr: 0xc0000ca000
28server ptr: 0xc0000ca000
29server ptr: 0xc0000ca000
30server ptr: 0xc0000ca000
31server ptr: 0xc0000ca000
32*/

懒汉式 - Goroutine安全

我们可以利用golang sync包提供的Once结构体来解决Goroutine安全问题。Once提供了在应用程序生命周期中仅会被调用一次的解决方案。我们将实例的生成过程使用Once保护起来,那么即可以做到单例。

 1package main
 2
 3import (
 4	"sync"
 5)
 6
 7type (
 8	server struct{}
 9)
10
11var (
12	instance *server
13	once     sync.Once
14)
15
16func getServerSingleton() *server {
17	once.Do(func() {
18		instance = &server{}
19	})
20
21	return instance
22}
23
24/*
25server ptr: 0x1182f88
26server ptr: 0x1182f88
27server ptr: 0x1182f88
28server ptr: 0x1182f88
29server ptr: 0x1182f88
30server ptr: 0x1182f88
31server ptr: 0x1182f88
32server ptr: 0x1182f88
33server ptr: 0x1182f88
34server ptr: 0x1182f88
35*/

用法

模拟10个并发请求获取单例。

 1func main() {
 2	wg := sync.WaitGroup{}
 3
 4	for index := 0; index < 10; index++ {
 5		wg.Add(1)
 6
 7		go func() {
 8			time.Sleep(time.Millisecond * 100)
 9
10			server := getServerSingleton()
11			fmt.Printf("server ptr: %p \n", server)
12
13			wg.Done()
14		}()
15	}
16
17	wg.Wait()
18}
comments powered by Disqus