Golang – 常用设计 Singleton Pattern

Singleton的用意就是在proram运行期间Global只有1个实例,一旦创建了就无法重复被创建

【Mutex方式】
使用mutex, 防止并发创建instance

    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    // Instance 结构体表示单例实例,包含一个名称字段。
    type Instance struct {
    	name string
    }
    
    // GlobalInstance 是指向单例实例的指针。
    var GlobalInstance *Instance
    
    // GlobalLock 用于同步对单例实例的访问。
    var GlobalLock sync.Mutex
    
    // getInstance 函数返回单例实例。如果实例不存在,则创建一个新实例。
    func getInstance(instanceName string) *Instance {
    	// 检查实例是否已经存在
    	if GlobalInstance == nil {
    		// 获取锁以防止并发创建实例
    		GlobalLock.Lock()
    		defer GlobalLock.Unlock()
    		// 再次检查以确保实例仍为nil,以防止竞态条件
    		if GlobalInstance == nil {
    			GlobalInstance = &Instance{
    				name: instanceName,
    			}
    		}
    	}
    	return GlobalInstance
    }
    
    func main() {
    	// 获取单例实例
    	instance1 := getInstance("instance1")
    	instance2 := getInstance("instance2")
    
    	// 打印实例的名称
    	fmt.Println("instance1 名称:", instance1.name)
    	fmt.Println("instance2 名称:", instance2.name)
    }
    

    输出结果:

    instance1 name: instance1
    instance2 name: instance1

    【Once.do 方式】
    使用Once来保证 某个对象只会初始化一次,有一点要要注意的是 这个 once.Do 只会被运行一次,哪怕 Do 函数里面的发生了异常,对象初始化失败了,这个 Do 函数也不会被再次执行了

    package main
    
    import (
    	"fmt"
    	"sync"
    )
    
    var (
    	GlobalInstance *Instance // 全局单例变量
    	GlobalOnce     sync.Once // 全局的 sync.Once 实例,确保单例只被初始化一次
    )
    
    type Instance struct {
    	name string // 单例实例的名称
    }
    
    // 获取单例实例的函数
    func getInstance(instanceName string) *Instance {
    	// 如果全局单例变量为 nil,则进行初始化
    	if GlobalInstance == nil {
    		GlobalOnce.Do(func() {
    			// 使用 sync.Once 确保此处的初始化逻辑只会执行一次
    			GlobalInstance = &Instance{
    				name: instanceName, // 初始化单例实例的名称
    			}
    		})
    	}
    	return GlobalInstance // 返回单例实例
    }
    
    func main() {
    	instance1 := getInstance("instance1") // 获取第一个实例
    	instance2 := getInstance("instance2") // 获取第二个实例
    	fmt.Println("instance1 name:", instance1.name) // 打印第一个实例的名称
    	fmt.Println("instance2 name:", instance2.name) // 打印第二个实例的名称
    }
    

    输出结果:

    instance1 name: instance1
    instance2 name: instance1

    Loading

    Facebook评论