1、单例模式

Go语言实现单例模式的有四种方式,分别是懒汉式、饿汉式、双重检查和 sync.Once。

懒汉式

非线程安全

package main

type Apple struct {
}

//私有变量
var apple *Apple

// GetAppleInstants 获取Apple实例
func GetAppleInstants() *Apple {
	if apple == nil {
		apple = new(Apple)
	}
	return apple
}

线程安全

双重检查锁

package main

import "sync"

//锁对象
var lock sync.Mutex

type Apple struct {
}

//私有变量
var apple *Apple

// GetAppleInstants 获取Apple实例
func GetAppleInstants() *Apple {
	if apple == nil {
		lock.Lock()
		defer lock.Unlock()
		if apple == nil {
			apple = new(Apple)
		}
	}
}

sync.Once

通过 sync.Once 来确保创建对象的方法只执行一次

package main

import "sync"

type Apple struct {
}
//once对象
var once sync.Once

//私有变量
var apple *Apple

// GetAppleInstants 获取Apple实例
func GetAppleInstants() *Apple {
	once.Do(func() {
		apple = new(Apple)
	})
}

sync.Once 内部本质上也是双重检查的方式,但在写法上会比自己写双重检查更简洁,以下是 Once 的源码

func (o *Once) Do(f func()) {
  //判断是否执行过该方法,如果执行过则不执行
    if atomic.LoadUint32(&o.done) == 1 {
        return
    }
    // Slow-path.
    o.m.Lock()
    defer o.m.Unlock()
  //进行加锁,再做一次判断,如果没有执行,则进行标志已经扫行并调用该方法
    if o.done == 0 {
        defer atomic.StoreUint32(&o.done, 1)
        f()
    }
}

饿汉式

使用全局变量

package main

type Apple struct {
}
//私有变量
var apple = new(Apple)

// GetAppleInstants 获取Apple实例
func GetAppleInstants() *Apple {
	return apple
}

使用init函数

package main

type Apple struct {
	
}
//私有变量
var apple *Apple

func init()  {
	apple = new(Apple)
}

// GetAppleInstants 获取Apple实例
func GetAppleInstants() *Apple {
	return apple
}