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 ...
随机推荐
- 团队作业8——Beta 阶段冲刺2rd day
一.今日站立式会议照片 二.每个人的工作 (1) 昨天已完成的工作: 今天是冲刺阶段的第二天,冲刺第一天我们完成了对于前端界面的改进与完善工作. (2) 今天计划完成的工作: 成员 昨天已完成的工作 ...
- Java多线程之Executor、ExecutorService、Executors、Callable、Future与FutureTask
1. 引子 初学Java多线程,常使用Thread与Runnable创建.启动线程.如下例: Thread t1 = new Thread(new Runnable() { @Override pub ...
- 【Beta阶段】第一次scrum meeting
Coding/OSChina 地址 1. 会议内容 学号 主要负责的方向 昨日任务 昨日任务完成进度 接下去要做 9 9 PM 博客编写,会议总结,代码整理 100% 准备下一次会议内容,并对已完成的 ...
- 201521123001《Java程序设计》第6周学习总结
1. 本周学习总结 1.1 面向对象学习暂告一段落,请使用思维导图,以封装.继承.多态为核心概念画一张思维导图,对面向对象思想进行一个总结. 注1:关键词与内容不求多,但概念之间的联系要清晰,内容覆盖 ...
- 201521123045 《Java程序设计》第5周学习总结
第5周-继承.多态.抽象类与接口 1. 本周学习总结 2. 书面作业 Q1.代码阅读:Child压缩包内源代码 1.1 com.parent包中Child.java文件能否编译通过?哪句会出现错误?试 ...
- 201521123075 《Java程序设计》第9周学习总结
1. 本周学习总结 2. 书面作业 本次PTA作业题集异常 1.常用异常 题目5-1 1.1 截图你的提交结果(出现学号) 1.2 自己以前编写的代码中经常出现什么异常.需要捕获吗(为什么)?应如何避 ...
- Easyui DataGrid DateRange Filter 漂亮实用的日期区间段筛选功能
自定义扩展Jquery easyui datagrid filter组件实现对日期类型区间段的筛选功能.显示效果如一下 是不是非常实用 引用的jquery 组件是 Date Range Picker ...
- Hibernate第九篇【组件映射、继承映射】
前言 到目前位置,我们已经学习了一对一.一对多.多对一.多对多映射了-既然Hibernate是ORM实现的框架,它还提供了组件映射和继承映射..本博文主要讲解组件映射和继承映射 Java主要的类主要有 ...
- .NET Core 使用RabbitMQ
RabbitMQ简介 AMQP,即Advanced Message Queuing Protocol,高级消息队列协议,是应用层协议的一个开放标准,为面向消息的中间件设计.消息中间件主要用于组件之间的 ...
- Docker入门之二镜像
Docker大部分的操作都是围绕三大核心概念:镜像.容器.仓库.学Docker首先得了解这几个词.这几个词可能平时也会有涉及,但Docker中可能不是同样得概念. 一.三大核心概念 镜像:可能在安装软 ...