设计模式-单例模式-GoLang模板

源自菜鸟教程

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。

这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

注意:

  • 1、单例类只能有一个实例
  • 2、单例类必须自己创建自己的唯一实例
  • 3、单例类必须给所有其他对象提供这一实例

在实现上有懒汉方式饿汉方式懒汉加锁双重锁sync.Once实现等不同的实现方法

区别:

1. 饿汉就是类一旦加载,就把单例初始化完成,保证GetInstance的时候,单例是已经存在的了

2. 而懒汉方式,只有当调用GetInstance的时候,会去初始化这个单例

3. 饿汉式天生就是线程安全的,可以直接用于多线程而不会出现问题

4. 懒汉式本身是非线程安全的,为了实现线程安全有几种写法

1. 懒汉方式

package main

import "fmt"

// 缺点:非线程安全;
// 当正在创建时,有线程来访问此时ins = nil就会再创建,单例类就会有多个实例了;

type Singleton struct{
    // 结构体中的一些字段
}
var instance *Singleton   // 全局的一个实例 

func GetInstance() *Singleton{
    if instance == nil {
        fmt.Println("懒汉方式--创建单例模式中的实例.")
        instance = &Singleton{}    //此处初始化实例
    }
    return instance
}

2. 饿汉方式

package main

import "sync"
import "fmt"

// 缺点是在导入包的同时会创建该对象,并持续占有在内存中

type Singleton struct{
	// 结构体中的一些字段
}

var instance *Singleton = &Singleton{}    // 此处已经创建好了

func GetInstance() *Singleton{
    return instance
}

3. 懒汉加锁

package main

import "sync"

import "fmt"

// Sync.Mutex进行加锁,保证线程安全,但由于每次调用该方法都进行了加锁操作,在性能上相对不高效

type Singleton struct {
	// 结构体中的一些字段
}

var instance *Singleton // 全局的一个实例
var m sync.Mutex        // 锁

func GetInstance() *Singleton {
    m.Lock()
    defer m.Unlock()
    if instance == nil {
        fmt.Println("懒汉加锁方式--创建单例模式中的实例.")
        instance = &Singleton{}
    }
    return instance
}

4. 双重锁/双重检查

package main

import "sync"

import "fmt"

// 在懒汉式(线程安全)的基础上再进行忧化,判少加锁的操作。保证线程安全同时不影响性能

type Singleton struct {
	// 结构体中的一些字段
}

var instance *Singleton // 全局的一个实例
var m sync.Mutex

func GetInstance() *Singleton {  
    if instance == nil {
        m.Lock()
        defer m.Unlock()
        if instance == nil {
            fmt.Println("双重检查方式--创建单例模式中的实例.")
            ins = &Singleton{}
        }
  } 

5. sync.Once(推荐)

package main

import "sync"

import "fmt"

type Singleton struct {
	// 结构体中的一些字段
}

var instance *Singleton // 全局的一个实例

var once sync.Once // sync.Once只有一个Do方法,可以保证这个函数f只执行一次  func (o *Once) Do(f func())

func GetInstance() *Singleton {
	once.Do(func() {
		fmt.Println("sync.Once方式--创建单例模式中的实例.")
		instance = &Singleton{} //此处初始化实例
	})
	return instance
}

补充:

1. sync.Once是golang提供的方法,一旦执行一次,就不再执行

2. 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()
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值