当前位置: 首页 > news >正文

Go 实现单例模式

单例模式是日常用到、常见的一种设计模式,但是其中有些细节还是值得说一说:

核心思想

  • 全局只有一个实例
  • 禁止外部直接创建对象
  • 提供统一入口获取实例
  • 多线程下必须安全

Go 单例模式实现

go 因为不是传统的面向对象语言,它没有类,也没有构造函数这种说法,这里最重要的是要解决封装的问题。
比如 java 的话,我们可以通过把类的构造函数改成私有的,从而达到禁止 new 的目的,这样类的使用者无法通过 new 来新建单例类的实例。
虽然无法通过 new 来创建实例,但是语言留了个口子,可以通过 static 来获取实例,这样单例类的创建者就可以控制该类的实例化方法了。
传统的 java 方案如下:

public class Singleton {// 禁止指令重排private static volatile Singleton instance;// 私有构造,禁止newprivate Singleton() {}public static Singleton getInstance() {if (instance == null) {           // 第一层:避免每次加锁,提升性能synchronized (Singleton.class) {if (instance == null) {    // 第二层:防止并发穿透,保证单例instance = new Singleton();}}}return instance;}
}

但是 java 没有类,也没有 static 的方式,那 go 要怎么处理呢?
实际上,go 可以用 结构体小写 + 全局变量 实现封装。

  • 结构体小写相当于构造函数小写禁止了 new
  • 全局变量相当于 static,虽然作用范围是包内,但是实际上它不是整个项目级别的全局变量,所以这里有点要强调的是 golang 的全局变量和 C 的全局变量还不太一样,它是介于 java static 变量和 C 全局变量之间的一种形式。

另外 go 标准库天然支持了 sync.Once 对并发友好,可以直接用:

package mainimport ("fmt""sync"
)// 定义单例结构体(首字母小写,外部无法直接创建,强制使用 GetInstance())
type singleton struct {// 业务字段Name string
}// 私有全局实例(首字母小写,外部无法直接访问)
var instance *singleton// 初始化执行器,保证只执行一次
var once sync.Once// GetInstance 公开方法:获取单例实例(唯一入口)
func GetInstance() *singleton {// 只会执行一次初始化once.Do(func() {fmt.Println("创建单例实例(仅执行一次)")instance = &singleton{Name: "我是全局唯一单例",}})return instance
}// 测试:多协程同时获取,验证只创建一次
func main() {var wg sync.WaitGroup// 开启 10 个协程同时获取单例for i := 0; i < 10; i++ {wg.Add(1)go func(num int) {defer wg.Done()ins := GetInstance()fmt.Printf("协程 %d:实例地址 = %p\n", num, ins)}(i)}wg.Wait()
}

其他传统写法:

package mainimport ("fmt""sync"
)type singleton struct {Name string
}var instance *singleton
var mu sync.Mutexfunc GetInstance() *singleton {// 加锁,防止多协程同时创建mu.Lock()defer mu.Unlock()if instance == nil {instance = &singleton{Name: "加锁懒汉式单例"}}return instance
}func main() {fmt.Println(GetInstance() == GetInstance()) // true
}
http://www.jsqmd.com/news/745476/

相关文章:

  • Linux系统网络解析
  • 百度网盘直链解析终极指南:三步告别限速烦恼
  • 教育科技公司如何利用Taotoken为学生提供个性化的编程练习反馈
  • 星露谷物语进阶指南:如何通过专业mod解决效率瓶颈,打造高效农场管理系统
  • 英飞凌MOSFET雪崩能量EAS怎么算?手把手教你用SOA图搞定不同应用场景
  • 别再硬查了!PostgreSQL里JSON字段的这几种查询姿势,总有一款适合你
  • 感受 Taotoken 按 token 计费模式带来的用量与成本可控性
  • 从GPS到PTP:深入拆解Livox雷达硬件时间同步原理,为你的SLAM系统打好‘时钟’基础
  • 畅享AI专著写作乐趣!专业工具一键生成20万字专著,查重率低至个位数
  • 终极STL体积计算器:3D打印材料成本一键搞定
  • 探索高效聊天机器人开发:Go-CQHTTP QQ机器人框架实用指南
  • 3步快速上手:Windows上安装APK的终极简单指南
  • 移动应用开发手册15:前端框架选型——Jetpack Compose、Flutter,傻傻分不清
  • 每月5块钱,长亭云图极速版ASM工具真能帮你发现漏洞吗?我的实测体验与避坑分享
  • 3个步骤让小爱音箱秒变AI语音助手:MiGPT终极配置指南
  • 台风数据采集全攻略:从数据源到实操落地
  • 告别TestFlight排队:用.mobileconfig和超级签实现iOS App内测分发(附PHP后端代码)
  • 电子产品热管理:设计思路与多案例图解(进阶高级工程师必看)
  • Sunshine游戏串流:5步搭建个人云游戏平台,随时随地畅玩3A大作
  • 从Arria到Agilex:Intel FPGA产品线变迁史,以及我们该如何选择?
  • TrafficMonitor插件终极指南:打造个性化Windows桌面监控中心
  • 使用Taotoken聚合端点后API调用的延迟与稳定性实际体验分享
  • 像 LOL 一样匹配 —— 动态绑定逻辑服与资源调度
  • Roblox 股价暴跌 18%:儿童安全措施影响预订量,下调 2026 年全年业绩指引
  • 【Azure App Service】为什么 Web App 上的文件会被锁死?
  • 深度解析ISO 9000七大原则:制造业质量管理体系的底层逻辑与数字化实践
  • B站缓存视频转换终极指南:免费快速解决m4s文件播放难题
  • 2024爆款AI工具推荐,助力AI写专著,快速生成20万字专著书稿!
  • sqli-labs第七关通关实录:当SQL注入遇上文件上传,我是如何用MySQL的into outfile拿到shell的
  • 5分钟快速上手:免费开源的跨平台语音AI框架sherpa-onnx终极指南