你真的会用go语言写单例模式吗?
最近在学习Golang,想着可以就以前的知识做一些串通,加上了解到go语言也是面向对象编程语言之后。在最近的开发过程中,我碰到一个问题,要用go语言实现单例模式。本着“天下知识,同根同源”(我瞎掰的~),我心想,这有什么难的,可是真正做起来,还是碰到了不少问题。
下面是我的经历:
1.我先是完成了我的第一版单例模式,就是非并发,最简单的一种,懒汉模式:
var instance *single
type single struct{
Name string
}
func GetInstance()*single{
if m == nil{
m = &single{}
}
return m
}
func main(){
a := GetInstance()
a.Name = "a"
b := GetInstance()
b.Name = "b"
fmt.Println(&a.Name, a)
fmt.Println(&b.Name, b)
fmt.Printf("%p %T\n", a, a)
fmt.Printf("%p %T\n", b, b)
}
结果如下:
0xc04203e1b0 &{b}
0xc04203e1b0 &{b}
0xc04203e1b0 *main.single
0xc04203e1b0 *main.single
可以看到,我们已经实现了简单的单例模式,我们申请了两次实例,在改变一个第二个实例的字段之后,第一个也随之改变了。而且从他们的地址都相同也可以看出是同一个对象。但是,这样简陋的单例模式在并发下就容易出错,非线程安全的。
现在我们是在并发的情况下去调用的 GetInstance函数,现在恰好第一个goroutine执行到m = &Manager {}这句话之前,第二个goroutine也来获取实例了,第二个goroutine去判断m是不是nil,因为m = &Manager{}还没有来得及执行,所以m肯定是nil,现在出现的问题就是if中的语句可能会执行两遍!
2.紧接着我们做了一些改进,给单例模式加了锁:
var m *single
var lock sync.Mutex
type single struct{
Name string
}
func GetInstance()*single{
lock.Lock()
defer lock.Unlock()
if m == nil{
m = &single{}
}
return m
}
结果同上。
与此同时,新的问题出现了,在高并发环境下,现在不管什么情况下都会上一把锁,而且加锁的代价是很大的,有没有办法继续对我们的代码进行进一步的优化呢?
3.双重锁机制:
var m *single
var lock sync.Mutex
type single struct{
Name string
}
func GetInstance()*single{
if m == nil{
lock.Lock()
defer lock.Unlock()
if m == nil{
m = &single{}
}
}
return m
}
这次我们用了两个判断,而且我们将同步锁放在了条件判断之后,这样做就避免了每次调用都加锁,提高了代码的执行效率。理论上写到这里已经是很完美的单例模式了,但是我们在go语言里,我们有一个很优雅的写法。
4.sync包里的Once.Do()方法
var m *single
var once sync.Once type single struct{
Name string
}
func GetInstance()*single{
once.Do(func() {
m = &single{}
})
return m
}
Once.Do方法的参数是一个函数,这里我们给的是一个匿名函数,在这个函数中我们做的工作很简单,就是去赋值m变量,而且go能保证这个函数中的代码仅仅执行一次!
以后在用go语言写单例模式的时候,可不要再傻傻的去使用前面那些例子了,既然已经有了优雅又强大的方法,我们直接用就完了。
你真的会用go语言写单例模式吗?的更多相关文章
- 你真的会写单例模式吗-------Java实现
转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...
- [转] 你真的会写单例模式吗——Java实现
你真的会写单例模式吗——Java实现 原文:http://www.tuicool.com/articles/MBrUfy6 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模 ...
- 自己用C语言写dsPIC / PIC24 serial bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). HyperBootlo ...
- 自己用C语言写单片机PIC18 serial bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). HyperBootlo ...
- 自己用C语言写单片机PIC16 serial bootloader
了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 为什么自己写bootl ...
- C语言写的流氓关机程序及破解
记得大二刚开始接触电脑的那个时候,偶尔会弹出一个强制关机的窗口,当时没有办法,如下: 现在看来只是一个小程序而已,用C语言编写的: #include<windows.h> int main ...
- php调用一个c语言写的接口问题
用php调用一个c语言写的soap接口时,遇到一个问题:不管提交的数据正确与否,都无法请求到接口 1.用php标准的soap接口去请求 2.拼接xml数据去请求 以上两种方式都不正确 解决办法:php ...
- PIC12F629帮我用C语言写个程序,控制三个LED亮灭
http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控 ...
- JAVA调用C语言写的SO文件
JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...
随机推荐
- lambda select和where区别
本文用一个linq to xml语法作为示例,以下是用来操作的xml:<?xml version="1.0" encoding="utf-8" stand ...
- 二、运行时JVM结构组成及作用
二.运行时JVM结构组成及作用 程序计数器 是否共享:否,线程私有,每个线程有1个独立的程序计数器! 所处位置:线程私有的内部区域 生命周期:与线程绑定 主要作用: 当前线程执行字节码的行号指示器! ...
- 字符串转json数组
import net.sf.json.JSONArray;import net.sf.json.JSONObject; String content = inBankOdd.getContent(). ...
- vue处理换行符
1.处理换行符 <tr class="unread" v-for="(item,index) in DataList" :key="index& ...
- linux同步onedrive文件
定时任务 # 开机自启动 @reboot /root/system/start.sh # 从零点开始每小时执行一次任务 0 0 0/1 * * ? nohup rclone sync onedrive ...
- 网络设备驱动程序-netdevice结构体关键部分注释
仅仅做个记录,内核4.19 struct net_device { char name[IFNAMSIZ]; //网络设备的名称 struct hlist_node name_hlist; char ...
- jmeter——参数化、关联、断言
1.jmeter——参数化 三种方式: ${变量名} 1.1用户定义的变量 比如注册,登录都得用到手机号码,那就把手机号码自定义为变量 1)添加一个线程组--注册.登录HTTP请求--察看结果树--用 ...
- Window脚本学习笔记之BAT调用设置
用一句bat脚本调用window的系统设置: rem 调用回收站 explorer.exe ::{645FF040-5081-101B-9F08-00AA002F954E} rem 检查Windows ...
- MySQL进阶8 分页查询(limit) - 【SQL查询语法执行顺序及大致结构】- 子查询的3个经典案例
#进阶8 分页查询 /* 应用场景: 当要显示的数据,一页显示不全,需要分页提交sql请求 语法: select 查询列表 #7 from 表1 #执行顺序:#1 [join type join 表2 ...
- Java集合--ArrayList,LinkedList性能分析
转载请注明出处:http://www.cnblogs.com/skywang12345/p/3308900.html 第1部分 List概括 先回顾一下List的框架图 (01) List 是一个接口 ...