最近在学习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语言写单例模式吗?的更多相关文章

  1. 你真的会写单例模式吗-------Java实现

    转载: 你真的会写单例模式吗--Java实现 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模式,还真得费一番脑筋.本文对Java中常见的单例模式写法做了一个总结,如有错漏 ...

  2. [转] 你真的会写单例模式吗——Java实现

    你真的会写单例模式吗——Java实现 原文:http://www.tuicool.com/articles/MBrUfy6 单例模式可能是代码最少的模式了,但是少不一定意味着简单,想要用好.用对单例模 ...

  3. 自己用C语言写dsPIC / PIC24 serial bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). HyperBootlo ...

  4. 自己用C语言写单片机PIC18 serial bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). HyperBootlo ...

  5. 自己用C语言写单片机PIC16 serial bootloader

    了解更多关于bootloader 的C语言实现,请加我QQ: 1273623966 (验证信息请填 bootloader),欢迎咨询或定制bootloader(在线升级程序). 为什么自己写bootl ...

  6. C语言写的流氓关机程序及破解

    记得大二刚开始接触电脑的那个时候,偶尔会弹出一个强制关机的窗口,当时没有办法,如下: 现在看来只是一个小程序而已,用C语言编写的: #include<windows.h> int main ...

  7. php调用一个c语言写的接口问题

    用php调用一个c语言写的soap接口时,遇到一个问题:不管提交的数据正确与否,都无法请求到接口 1.用php标准的soap接口去请求 2.拼接xml数据去请求 以上两种方式都不正确 解决办法:php ...

  8. PIC12F629帮我用C语言写个程序,控制三个LED亮灭

    http://power.baidu.com/question/240873584599025684.html?entry=browse_difficult PIC12F629帮我用C语言写个程序,控 ...

  9. JAVA调用C语言写的SO文件

    JAVA调用C语言写的SO文件 因为工作需要写一份SO文件,作为手机硬件IC读卡和APK交互的桥梁,也就是中间件,看了网上有说到JNI接口技术实现,这里转载了一个实例 // 用JNI实现 // 实例: ...

随机推荐

  1. RestControllerAdvice,ControllerAdvice

    1.切记@RestControllerAdvice 和 @ControllerAdvice 不能放在common里,会不生效,还会引起子项目的全局异常失败. 所以这2个还是放在各自的子项目里去处理.一 ...

  2. GIL锁、进程池与线程池、同步异步

    GIL锁定义 GIL锁:Global Interpreter Lock  全局解释器 本质上是一把互斥锁 官方解释: 在CPython中,这个全局解释器锁,也称为GIL,是一个互斥锁,防止多个线程在同 ...

  3. vulnhub攻略

    https://www.vulnhub.com/entry/21ltr-scene-1,3/ 这个靶机国内https://www.cnblogs.com/hack404/p/11423228.html ...

  4. sql server存储过程返回数据只有一个字符

    SqlParameter[] param = { new SqlParameter("@shopId",shopId), new SqlParameter("@newSh ...

  5. centos根目录扩容,home目录减小容量

    参考: https://blog.csdn.net/evandeng2009/article/details/49814097 主要命令: 15 cd / 16 ll 17 mkdir backup ...

  6. 【Hibernate】持久化对象状态及以及缓存

    一.持久化类状态 1.1 三种持久化对象的状态 1.2 区分三种状态 1.3 三种状态对象转换 1.瞬时态 2.持久态 3.脱管态 4.持久态对象有自动更新数据库的能力 一.持久化类状态 1.1 三种 ...

  7. “高可用性”(High Availability)??

    “高可用性”(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性. 计算机的高可用性 计算机系统的可用性用平均无故障时间(MTTF)来度量 ...

  8. Ubuntu系统---报错Assertion '0' failed

    Ubuntu系统---报错Assertion '0' failed YOLO V3,CUDA Error: out of memory darknet: ./src/cuda.c:36: check_ ...

  9. 【jmeter】无GUI界面,命令行运行测试脚本

    一.应用场景 1.无需交互界面或受环境限制(linux text model) 2.远程或分布式执行 3.持续集成,通过shell脚本或批处理命令均可执行,生成的测试结果可被报表生成模块直接使用,便于 ...

  10. 前端笔记-dom

    dom(document object model) -文档对象模型,包含整个页面所有功能,可以通过调用方法的形式来操作页面,所以js和dom结合在一起可以写一些逻辑性的语言 dom的对象 dom有5 ...