最近在学习Golang,想着可以就以前的知识做一些串通,加上了解到go语言也是面向对象编程语言之后。在最近的开发过程中,我碰到一个问题,要用go语言实现单例模式。本着“天下知识,同根同源”(我瞎掰的~),我心想,这有什么难的,可是真正做起来,还是碰到了不少问题。

  下面是我的经历:

  1.我先是完成了我的第一版单例模式,就是非并发,最简单的一种,懒汉模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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.紧接着我们做了一些改进,给单例模式加了锁:

1
2
3
4
5
6
7
8
9
10
11
12
13
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.双重锁机制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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()方法

1
2
3
4
5
6
7
8
9
10
11
12
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 -- 单例的更多相关文章

  1. java单例设计模式

    单例模式的特点: 1.单例类只能有一个对象(实例). 2.单例类必须自己创建自己的唯一实例 . 3.单例类必须给所有其他对象提供这一实例. 设置步骤: 1.将对象的应用成员变量用private来修饰. ...

  2. DBUtil数据库连接单例 —— 简单不简单

    单例大概是我最早产生明确模式意识的设计模式,因为它足够简单粗暴,目的足够明确. 单例么,就是不管怎么访问,都返回一个单一实例就好了,我最早应用在数据库的DBUtil中. public class DB ...

  3. SSH中Action的单例与多例

    Structs2中的Bean默认的是单例,在整个程序运行期间,每个Bean只有一个实例,只要程序在运行,这个实例就一直存在. 对于Action来说,单例就容易出问题.如果客户端每次提交的参数都是一样的 ...

  4. 《连载 | 物联网框架ServerSuperIO教程》- 8.单例通讯模式开发及注意事项

    1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架Serve ...

  5. static实现单例的隐患

    1. 前言 Java的单例有多种实现方式:单线程下的简单版本.无法在指令重排序下正常工作的Double-Check.static.内部类+static.枚举--.这篇文章要讨论的,是在使用static ...

  6. 架构师养成记--6.单例和多线程、ThreadLocal

    一.ThreadLocal 使用wait/notify方式实现的线程安全,性能将受到很大影响.解决方案是用空间换时间,不用锁也能实现线程安全. 来看一个小例子,在线程内的set.get就是thread ...

  7. 在Swift中实现单例方法

    在写Swift的单例方法之前可以温习一下Objective-C中单例的写法: + (instancetype)sharedSingleton{ static id instance; static d ...

  8. Javascript设计模式学习二(单例)

    定义:保证一个类仅有一个实例,并提供一个访问它的全局访问点 普通的单例模式: 使用一个变量来标记当前是否已经为某个类创建过对象,如果是的话,在下一次获取该类的实例时,直接返回之前创建的对象.比如:使用 ...

  9. OC与Swift单例

    OC: +(instancetype)shareNetworkTools{ static id instance; static dispatch_once_t onceToken; //onceTo ...

  10. 【iOS 单例设计模式】底层解析与运用

    [iOS 单例设计模式]底层解析与运用 一.单例设计名词解释: (官方解释)单例模式确保一个类只有一个实例,自行提供这个实例并向整个系统提供这个实例.(形象比喻)程序 — 公司   单例实例 - 管理 ...

随机推荐

  1. 怎么能让json_decode解析带斜杠的字符串

    比如前台一个js object:{  aa: "cc\dd"}$d = '{\"aa\": \"cc\\dd\"}';这时候用 json_d ...

  2. Elasticsearch5.0 安装问题

    使用Elasticsearch5.0 必须安装jdk1.8 [elsearch@vm-mysteel-dc-search01 bin]$ java -version java version &quo ...

  3. Rookey.Frame之数据库及缓存配置

    上一篇中讨论了Rookey.Frame框架菜单配置功能,这一节我们继续学习Rookey.Frame框架的数据库连接配置. 之前介绍了Rookey.Frame框架支持跨多数据库,并且支持读写分离,不过目 ...

  4. TypeScript的数据类型总结

    全局下载:npm i typescript -g 编译.ts文件:tsc  1.ts自动生成对应js文件 基本类型: 1.布尔,数字,字符串 ts文件 //布尔类型 var a:boolean=tru ...

  5. 基于 Laravel 开发博客应用系列 —— Homestead 和 Laravel 安装器

    1.Homestead 从主机操作系统的控制台中(Windows 中被称作命令提示符,Linux 中被称作终端),你可以轻松通过不带参数的homestead 命令查看所有有效的 Homestead 命 ...

  6. React Native性能优化之可取消的异步操作

    前沿 在前端的项目开发中,异步操作是一个不可获取的,从用户的角度来说,异步操作所带来的体验是美妙的,但有时候也会带来一些性能隐患.比如说:有一个异步请求还没有返回结果,但是页面却关闭了,这时由于异步操 ...

  7. 让Xcode8.0支持iOS11.2设备真机测试

    最新支持11.2 (15C5097c)! 11.1 全版本! Xcode只可以支持iPhone手机对应iOS系统以下的真机测试.一般想要支持最新的iPhone手机系统,有两个方法. 第一.就需要更新X ...

  8. BZOJ.2428.[HAOI2006]均分数据(随机化贪心/模拟退火)

    题目链接 模拟退火: 模拟退火!每次随机一个位置加给sum[]最小的组. 参数真特么玄学啊..气的不想调了(其实就是想刷刷最优解) 如果用DP去算好像更准.. //832kb 428ms #inclu ...

  9. [AGC016E]Poor Turkeys

    [AGC016E]Poor Turkeys 题目大意: 有\(n(n\le400)\)只火鸡,编号为\(1\)到\(n\),有\(m(m\le10^5)\)个人,每人指定了两只火鸡\(x\)和\(y\ ...

  10. Gunicorn配置部分的翻译

    写在前面,虽然翻译得很烂,但也是我的劳动成果,转载请注明出处,谢谢. Gunicorn版本号19.7.1 Gunicorn配置 概述 三种配置方式 优先级如下,越后的优先级越大 1.框架的设置(现在只 ...