Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

对单例模式实现代码的建议 #21

Closed
dakangshuji opened this issue Aug 18, 2021 · 2 comments
Closed

对单例模式实现代码的建议 #21

dakangshuji opened this issue Aug 18, 2021 · 2 comments

Comments

@dakangshuji
Copy link

给出的demo代码的确能跑通,但是利用sync.Once.Do()方法实现线程安全的话,会导致整个go进程中只能创建这一种单例
如果我想创建多个用处不同的单例的话,会导致后面的都没法成功

想了两种优化的方案

  1. 每次都先加线程锁,再判断实例
package singleton

import (
	"sync"
)

// Singleton 是单例模式接口,导出的
// 通过该接口可以避免 GetInstance 返回一个包私有类型的指针
type Singleton interface {
	foo()
}

// singleton 是单例模式类,包私有的
type singleton struct{}

func (s singleton) foo() {}

var (
	instance  *singleton
	instance2 *singleton2
	mu        sync.Mutex
)

//GetInstance 用于获取单例模式对象
func GetInstance() Singleton {
	mu.Lock()
	defer mu.Unlock()
	if instance == nil {
		instance = &singleton{}
	}

	return instance
}

type singleton2 struct {
}

func (s2 singleton2) foo() {}
func GetInstance2() Singleton {
	mu.Lock()
	defer mu.Unlock()
	if instance2 == nil {
		instance2 = &singleton2{}
	}
	return instance2
}

  1. 每次先用sync/atomic判断,再加锁判断实例
package singleton

import (
	"sync"
	"sync/atomic"
)

// Singleton 是单例模式接口,导出的
// 通过该接口可以避免 GetInstance 返回一个包私有类型的指针
type Singleton2 interface {
	foo()
}

// singleton 是单例模式类,包私有的
type singleton21 struct{}

func (s singleton21) foo() {}

var (
	instance21       *singleton21
	instance22       *singleton22
	initInstanceCnt  uint32
	initInstanceCnt2 uint32
	mu               sync.Mutex
)

//GetInstance 用于获取单例模式对象
func GetInstance21() Singleton2 {
	if atomic.LoadUint32(&initInstanceCnt) == 1 {
		return instance21
	}

	mu.Lock()
	defer mu.Unlock()

	if initInstanceCnt == 0 {
		instance21 = &singleton21{}
		atomic.StoreUint32(&initInstanceCnt, 1)
	}
	return instance21
}

type singleton22 struct {
}

func (s2 singleton22) foo() {}
func GetInstance22() Singleton {
	if atomic.LoadUint32(&initInstanceCnt2) == 1 {
		return instance22
	}

	mu.Lock()
	defer mu.Unlock()

	if initInstanceCnt2 == 0 {
		instance22 = &singleton22{}
		atomic.StoreUint32(&initInstanceCnt2, 1)
	}
	return instance22
}

@senghoo
Copy link
Owner

senghoo commented Aug 18, 2021

我觉得这方面用什么上锁模式其实没什么太大差别。用互斥锁、原子变量还是用Once。(其实Once内部实现就是原子变量),就是看起来语意更清晰一些。

就算用Once,也可以实现多个实例 也就是多一个Once,还有工厂函数和全局变量。

@dakangshuji
Copy link
Author

我觉得这方面用什么上锁模式其实没什么太大差别。用互斥锁、原子变量还是用Once。(其实Once内部实现就是原子变量),就是看起来语意更清晰一些。

就算用Once,也可以实现多个实例 也就是多一个Once,还有工厂函数和全局变量。

你说的有道理,我后来又试了一下,的确是声明多个once就可以了。看来是我误解了sync.Once.Do()的用法

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants