使用sync.Once实现Go语言线程安全单例,确保多协程下仅初始化一次,避免竞态条件,代码简洁可靠。

在Go语言中,单例模式常用于确保某个类型在整个程序生命周期中仅存在一个实例,比如配置管理、数据库连接池等场景。实现线程安全的单例模式,sync.Once 是最推荐的方式,它能保证初始化操作只执行一次,且在多协程环境下安全可靠。
单例模式核心问题
多协程环境下,多个 goroutine 同时调用单例获取实例时,可能造成多次初始化。传统加锁方式虽然可行,但代码复杂且容易出错。Go 标准库中的 sync.Once 提供了简洁高效的解决方案。
使用 sync.Once 实现线程安全单例
以下是基于 sync.Once 的典型实现方式:
package singleton
import (
"sync"
)
// 单例结构体
type Singleton struct {
Data string
}
var (
instance *Singleton
once sync.Once
)
// GetInstance 返回单例实例,线程安全
func GetInstance() *Singleton {
once.Do(func() {
instance = &Singleton{
Data: "initialized",
}
})
return instance
}
关键点说明:
立即学习“go语言免费学习笔记(深入)”;
BJXShop网上购物系统是一个高效、稳定、安全的电子商店销售平台,经过近三年市场的考验,在中国网购系统中属领先水平;完善的订单管理、销售统计系统;网站模版可DIY、亦可导入导出;会员、商品种类和价格均实现无限等级;管理员权限可细分;整合了多种在线支付接口;强有力搜索引擎支持... 程序更新:此版本是伴江行官方商业版程序,已经终止销售,现于免费给大家使用。比其以前的免费版功能增加了:1,整合了论坛
- once.Do(...) 确保传入的函数只执行一次,即使多个 goroutine 同时调用也不会重复初始化。
- 后续调用 GetInstance() 直接返回已创建的 instance,无性能损耗。
- 无需手动加锁,由 sync.Once 内部保障原子性。
测试线程安全性
可以通过启动多个 goroutine 来验证单例是否真正唯一:
package main
import (
"fmt"
"sync"
"your-package/singleton"
)
func main() {
var wg sync.WaitGroup
for i := 0; i < 10; i++ {
wg.Add(1)
go func() {
defer wg.Done()
obj := singleton.GetInstance()
fmt.Printf("Instance address: %p\n", obj)
}()
}
wg.Wait()
}
输出结果中所有地址都相同,说明无论多少协程调用,实例始终唯一。
懒加载与性能优势
这种实现是懒加载的——实例在第一次调用 GetInstance() 时才创建,避免程序启动时不必要的开销。同时,sync.Once 内部做了优化,一旦初始化完成,后续调用几乎无额外开销。
基本上就这些。用 sync.Once 写单例,简单、安全、高效,是Go中最推荐的做法。









