Go 单例模式[个人翻译]
原文地址:http://marcio.io/2015/07/singleton-pattern-in-go/
常识性错误
最近,我在很多Github库里看到这种类型的错误,单例模式的实现没有考虑线程安全,下面是常识性错误的代码
package singleton
type singleton struct {
}
var instance *singleton
func GetInstance() *singleton {
if instance == nil {
instance = &singleton{} // <---非线程安全的
}
return instance
}
激进的锁
我也看到一些使用糟糕的方法来解决线程安全的问题。事实上他解决了多线程的问题,但是创造了其他潜在的更严重的问题,他通过对整个方法执行锁定来引入线程竞争
var mu Sync.Mutex
func GetInstance() *singleton {
mu.Lock() // <--- 如果实例已经被创建就没有必要锁写
defer mu.Unlock()
if instance == nil {
instance = &singleton{}
}
return instance
}
Check-Lock-Check 模式
在c++和其他语言,用于保证最小锁定并且保证线程安全的最好、最安全的方式是当需要锁定时使用众所周知的Check-Lock-Check模式。下面的伪代码说明了这个模式的大概样子
if check() {
lock() {
if check() {
// perform your lock-safe code here
}
}
}
func GetInstance() *singleton {
if instance == nil { // <-- 不够完善. 他并不是完全的原子性
mu.Lock()
defer mu.Unlock()
if instance == nil {
instance = &singleton{}
}
}
return instance
}
import "sync"
import "sync/atomic" var initialized uint32
... func GetInstance() *singleton { if atomic.LoadUInt32(&initialized) == {
return instance
} mu.Lock()
defer mu.Unlock() if initialized == {
instance = &singleton{}
atomic.StoreUint32(&initialized, )
} return instance
}
但是.....我相信我们可以通过查看Go语言和标准库的源码看一下go routines 同步的实现方式来做的更好
Go惯用的单例方法
我们想要使用Go的惯用手法来实现这个单例模式。所以我们需要看一下打包好的sync标准库。我们找到了 Once 类型。这个对象可以精确的只执行一次操作,下面就是Go标准库的代码
// Once is an object that will perform exactly one action.
type Once struct {
m Mutex
done uint32
} // Do calls the function f if and only if Do is being called for the
// first time for this instance of Once. In other words, given
// var once Once
// if once.Do(f) is called multiple times, only the first call will invoke f,
// even if f has a different value in each invocation. A new instance of
// Once is required for each function to execute.
//
// Do is intended for initialization that must be run exactly once. Since f
// is niladic, it may be necessary to use a function literal to capture the
// arguments to a function to be invoked by Do:
// config.once.Do(func() { config.init(filename) })
//
// Because no call to Do returns until the one call to f returns, if f causes
// Do to be called, it will deadlock.
//
// If f panics, Do considers it to have returned; future calls of Do return
// without calling f.
//
func (o *Once) Do(f func()) {
if atomic.LoadUint32(&o.done) == { // <-- Check
return
}
// Slow-path.
o.m.Lock() // <-- Lock
defer o.m.Unlock()
if o.done == { // <-- Check
defer atomic.StoreUint32(&o.done, )
f()
}
}
这意味着我们可以运用非常棒的 Go sync包来调用一个只执行一次的方法。因此,我们可以向下面这样调用 once.Do() 方法
once.Do(func() {
// 执行安全的初始化操作
})
下面你可以看到使用sync.Once类型实现的单例实现的完整代码,用于同步访问GetInstance() 并保证我们的类型初始化只执行一次。
package singleton import (
"sync"
) type singleton struct {
} var instance *singleton
var once sync.Once func GetInstance() *singleton {
once.Do(func() {
instance = &singleton{}
})
return instance
}
总结
Go 单例模式[个人翻译]的更多相关文章
- Go语言中的单例模式(翻译)
在过去的几年中,Go语言的发展是惊人的,并且吸引了很多由其他语言(Python.PHP.Ruby)转向Go语言的跨语言学习者. Go语言太容易实现并发了,以至于它在很多地方被不正确的使用了. Go语言 ...
- Go语言之路—博客目录
Go语言介绍 为什么你应该学习Go语言? 开发环境准备 从零开始搭建Go语言开发环境 VS Code配置Go语言开发环境 Go语言基础 Go语言基础之变量和常量 Go语言基础之基本数据类型 Go语言基 ...
- [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)
以下内容为原创,欢迎转载,转载请注明 来自天天博客:http://www.cnblogs.com/tiantianbyconan/p/5095426.html 使用Dagger 2依赖注入 - 自定义 ...
- 【白话设计模式四】单例模式(Singleton)
转自:https://my.oschina.net/xianggao/blog/616385 0 系列目录 白话设计模式 工厂模式 单例模式 [白话设计模式一]简单工厂模式(Simple Factor ...
- Java中的GOF23(23中设计模式)--------- 单例模式(Singleton)
Java中的GOF23(23中设计模式)--------- 单例模式(Singleton) 在Java这这门语言里面,它的优点在于它本身的可移植性上面,而要做到可移植的话,本身就需要一个中介作为翻译工 ...
- 【Java】Java 深入探讨 单例模式的实现
在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在 ...
- 深入Java单例模式【转载】
在GoF的23种设计模式中,单例模式是比较简单的一种.然而,有时候越是简单的东西越容易出现问题.下面就单例设计模式详细的探讨一下. 所谓单例模式,简单来说,就是在整个应用中保证只有一个类的实例存在 ...
- spring aop配置文档部分翻译
欢迎转载交流: http://www.cnblogs.com/shizhongtao/p/3476973.html 下面的文字来自官方文档的翻译,具体事例以后奉上. Advisors "ad ...
- Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译)
# 禅与 Objective-C 编程艺术 (Zen and the Art of the Objective-C Craftsmanship 中文翻译) - 原文 <https://githu ...
随机推荐
- 201521123076《Java程序设计》第1周学习总结
一. 本章学习总结 1.了解了JDK,JVM,JRE的相关内容 JVM(Java Virtual Machine): Java虚拟机,*.java原始码,经过编译程序翻译为.class位码.JVM正是 ...
- 201521123056 《Java程序设计》第12周学习总结
1. 本周学习总结 2. 书面作业 将Student对象(属性:int id, String name,int age,double grade)写入文件student.data.从文件读出显示. 1 ...
- 201521123018 《Java程序设计》第13周学习总结
1. 本章学习总结 2. 书面作业 一.1. 网络基础 1.1 比较ping www.baidu.com与ping cec.jmu.edu.cn,分析返回结果有何不同?为什么会有这样的不同? 返回时间 ...
- JSP引入 - UEditor 富文本编辑器
UEditor JSP 因为是项目第一天就导入了,现在过去一个多星期了,可能会有问题 官网:http://ueditor.baidu.com/website/ 1. 解压对应的UEditor压缩包至 ...
- 从instr中截取第一个delimiter之前的内容放到outstr中,返回第一个delimiter之后的位置
从instr中截取第一个delimiter之前的内容放到outstr中,返回第一个delimiter之后的位置 char *msstrtok(char *instr, char *outstr, ch ...
- 如何加固Linux系统
如何加固Linux系统 一. 账户安全 1.1 锁定系统中多余的自建帐号 检查方法: 执行命令 #cat /etc/passwd #cat /etc/shadow 查看账户.口令文件,与系统管理员确认 ...
- Java对象克隆详解
原文:http://www.cnblogs.com/Qian123/p/5710533.html 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = appl ...
- MySql 中文乱码解决办法
mysql存入的中文数据乱码,可能有这两个原因 原因一 : 数据源配置和mysql字符集编码不符,或数据源配置没有设置字符集 解决方案:在数据源配置添加字符集 useUnicode=true& ...
- LuoguP1196_银河英雄传说_KEY
银河英雄传说 题目描述 公元5801年,地球居民迁移至金牛座α第二行星,在那里发表银河联邦创立宣言,同年改元为宇宙历元年,并开始向银河系深处拓展. 宇宙历799年,银河系的两大军事集团在巴米利恩星域爆 ...
- css左右布局的几种实现方式和优缺点
记录一下左右布局的实现方式,实现的具体效果是,左侧固定宽度,高度适中等于父元素的高度,父元素的高度由右侧内容决定: html代码如下: <div class="parent" ...