go语言中单例模式需确保结构体仅初始化一次且线程安全;2. 推荐使用sync.Once保证唯一性和并发安全;3. 示例中GetInstance通过once.Do确保初始化逻辑仅执行一次;4. 多goroutine测试验证了实例唯一与线程安全;5. sync.Once底层通过互斥锁和标志位实现,确保内存同步与原子性。
在go语言中,单例模式的实现需要确保在整个程序生命周期中某个结构体仅被初始化一次,并且在多协程环境下线程安全。最推荐的方式是使用 sync.Once 来保证初始化的唯一性和并发安全。
单例模式核心问题
单例的关键在于:实例只能创建一次,即使多个 goroutine 同时访问,也不能重复创建。常见的错误做法是使用全局变量加 if 判断,但这在并发场景下会出问题。
使用 sync.Once 实现线程安全单例
sync.Once 能确保某个函数在整个程序运行期间只执行一次,非常适合用于单例初始化。
示例代码:
package main import ( "fmt" "sync" ) type Singleton struct { data string } var instance *Singleton var once sync.Once func GetInstance() *Singleton { once.Do(func() { instance = &Singleton{ data: "I am the only instance", } fmt.Println("Singleton instance created") }) return instance }
在这个实现中:
立即学习“go语言免费学习笔记(深入)”;
- GetInstance() 是获取单例实例的唯一入口
- once.Do() 内的初始化逻辑只会执行一次,无论多少个 goroutine 同时调用
- 后续调用直接返回已创建的 instance
测试并发安全性
可以启动多个 goroutine 来验证是否真的只初始化一次:
func main() { var wg sync.WaitGroup for i := 0; i < 10; i++ { wg.Add(1) go func() { defer wg.Done() obj := GetInstance() fmt.Printf("Got instance: %p, data: %sn", obj, obj.data) }() } wg.Wait() }
输出结果中,“Singleton instance created” 只会打印一次,所有 goroutine 获取的是同一个实例地址,证明线程安全且唯一。
为什么 sync.Once 是可靠的?
sync.Once 的底层通过互斥锁和标志位双重检查来实现,Go 运行时保证了内存同步和原子性。即使在多核 CPU 上,也能防止重排序和竞态条件。
基本上就这些。用 sync.Once 实现单例简洁、安全、高效,是 Go 中最标准的做法。
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END