Go 语言实现 23 种设计模式 单例模式

Go 语言实现 23 种设计模式 单例模式

单例模式

单例模式是一种常用的软件设计模式,在使用过程中,单例对象的类只有一个实例。使用单例模式,1 可以节省内存等资源,例如windows操作系统的资源管理器只有一个就够了。2 方便配置管理,例如,服务器的配置信息存放在一个文件中,配置信息由一个单例实例统一读取,进场中的其他对象通过这个单例实例获取配置信息。

实例1

下面这段代码有什么问题,从多线程角度思考,就会发现下面的代码是非线程安全的,比如有两个线程都在调用NewInstance1函数,线程A在执行到if instance==nil后 cpu切换到线程B执行,直到线程B运行完,这时instance已经被实例化,当cpu在切回到线程A继续执行的时候,对instance又执行实例化操作,这时内存中已有Instance的两个实例,违背了单例定义。

type Instance struct{}//非线程安全
func NewInstance1() *Instance {if instance == nil {instance = &Instance{}}return instance
}

实例2

var lock sync.Mutex//lock-check模式
func NewInstance2() *Instance {lock.Lock()defer lock.Unlock()if instance == nil {instance = &Instance{}}return instance
}

实例3

实例3采用的是先判断方式,如果instance已经被实例化,直接返回就行了。如果没有实例化,在进行加锁创建实例,即执行实例2的操作。这样就可以并发执行。上面的实例2是先lock在check方式,简称lock-check模式,实例称为check-lock-check模式。继续思考,实例3有没有问题呢?if instance==nil是原子操作吗?

//check-lock-check模式
func NewInstance3() *Instance {if instance == nil {lock.Lock()if instance == nil {instance = &Instance{}}lock.Unlock()}return instance
}

实例4

既然实例3 比较操作是非原子操作,那将比较这句改成原子操作,golang 提供了原子操作package atomic,申请一个uint32变量做标记,如果是1表示已实例化,如果是0表示么有实例化。实例4已经非常好了,在golang有么有更好的方法呢,

var initlized uint32//check-lock-check
func NewInstance4() *Instance {if atomic.LoadUint32(&initlized) == 1 {return instance}lock.Lock()defer lock.Unlock()if initlized == 0 {instance = &Instance{}atomic.StoreUint32(&initlized, 1)}return instance}

实例5

在golang中,atomic包中提供一个sync.Once类型,该类型有个Do方法,只会执行一次,
所以将实例化方法放在Do中,只会实例化一次,非常完美的方法,所以实例5是最佳实践方法。

func NewInstance5() *Instance {if instance == nil {once.Do(func() {instance = &Instance{}})}return instance
}

分析总结

在写代码的时候,要保证正确性第一,然后在考虑性能优化的问题,实例1和实例3在正确性上没有保证。
其次才是考虑性能优化,有没有更好的方法,像实例2性能不友好,实例4就比实例2有提升,实例5是最佳实践方法。
当然实例3方法可以放在init函数中调用,进程启动之后再掉用其实也没有问题,因为instance已经被实例化过了。

程序的运行中只产生一个实例

Example_one

type Singleton struct {id int
}var TestSingleton *Singleton
var singletonMutex sync.Mutexfunc NewSingleton() *Singleton {if TestSingleton == nil {singletonMutex.Lock()defer singletonMutex.Unlock()if TestSingleton == nil {TestSingleton = &Singleton{0}}}return TestSingleton
}

Example_two

func NewSingleton() *Singleton {once.Do(func() {TestSingleton = &Singleton{0}})return TestSingleton
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/382044.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Go 语言实现 23 种设计模式适配器

Go 语言实现 23 种设计模式适配器 将一个类型的接口转换成客户希望的另外一个接口,使原本由于接口不兼容而不能一起工作的类可以一起工作。 Example_one package mainimport "fmt"// Adaptee 适配者 type MyLegacyPrinter struct{}func (l *MyLegacyPr…

go设计模式思维导图

go设计模式思维导图

uva 1610——Party Games

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id51171 题意:给你n个串的集合D,然后求一个长度最短的串s,使得使得s大于等于D中一半的串,又同时小于另一半串。 思路:直接暴力。先对…

链表相加 2. 两数相加

2. 两数相加 给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。 如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。 您可以…

uva10780 - Again Prime? No time

uva10780 - Again Prime? No timeAgain Prime? No time. The problem statement is very easy. Given a number n you have to determine the largest power of m, not necessarily prime, that divides n!. Input The input file consists of several test cases. The first…

303. 区域和检索 - 数组不可变

303. 区域和检索 - 数组不可变 给定一个整数数组 nums,求出数组从索引 i 到 j (i ≤ j) 范围内元素的总和,包含 i, j 两点。 示例: 给定 nums [-2, 0, 3, -5, 2, -1],求和函数为 sumRange() sumRange(0, 2) -> 1 sumRange…

【转载】最短路径之Dijkstra算法详细讲解

1 最短路径算法 在日常生活中,我们如果需要常常往返A地区和B地区之间,我们最希望知道的可能是从A地区到B地区间的众多路径中,那一条路径的路途最短。最短路径问题是图论研究中的一个经典算法问题, 旨在寻找图&#xf…

Intelij 添加php注释

没有methodParameters()) groovyScript("def result; def params\"${_1}\".replaceAll([\\\\[|\\\\]|\\\\s], ).split(,).toList(); for(i 0; i < params.size(); i) {result * param params[i] ((i < params.size() - 1) ? \\n:)}; return result…

HDU 2544 最短路(各种最短路算法的实现)

链接&#xff1a; http://acm.hdu.edu.cn/showproblem.php?pid2544 题目&#xff1a; Problem Description 在每年的校赛里&#xff0c;所有进入决赛的同学都会获得一件很漂亮的t-shirt。但是每当我们的工作人员把上百件的衣服从商店运回到赛场的时候&#xff0c;却是非常累的…

为什么LeetCode过一段时间又不会了

怎么从这个迷宫的左上角走到右下角&#xff1f; 看起来好像很简单&#xff0c;花时间还是可以找得到答案。 看了答案之后可以很清楚&#xff0c;这是正解。 只有一个问题&#xff1a; 我怎么就没立刻想到&#xff1f; 当在看题解或者听别人讲授思路的时候&#xff0c;你就是…

148. 排序链表

148. 排序链表 给你链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排序后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [4,2,1,3] 输出&#xff1a;[1,2,3,4] 示例 2&#xff1a; 输入&#xff1a;head [-1,5,3,4,0] 输出&#xff1a;[-1,0,3,4,5] 示…

POJ 3660 Cow Contest(传递闭包floyed算法)

Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming contest. As we all know, some cows code better than others. Each cow has a certain constant skill rating that is unique among the competitors. The contest is…

23. 合并K个升序链表

23. 合并K个升序链表 给你一个链表数组&#xff0c;每个链表都已经按升序排列。 请你将所有链表合并到一个升序链表中&#xff0c;返回合并后的链表。 示例 1&#xff1a; 输入&#xff1a;lists [[1,4,5],[1,3,4],[2,6]] 输出&#xff1a;[1,1,2,3,4,4,5,6] 解释&#xf…

HDU 1874 畅通工程续 (Dijkstra , Floyd , SPFA, Bellman_Ford 四种算法)

畅通工程续 题目链接&#xff1a;http://acm.hdu.edu.cn/showproblem.php?pid1874 Problem Description 某省自从实行了很多年的畅通工程计划后&#xff0c;终于修建了很多路。不过路多了也不好&#xff0c;每次要从一个城镇到另一个城镇时&#xff0c;都有许多种道路方案可以…

训练指南——数学专题一的总结

差不多一个星期过去了&#xff0c;在这一个多星期里&#xff0c;我做了一个数学专题和两场训练赛&#xff0c;要说对自己的感觉&#xff0c;只能说很差劲&#xff0c;开始的时候以为环境会比现在宽松很多&#xff0c;后来才发现想法是错误的&#xff0c;实验室室里室一种紧张的…

micro/protoc-gen-micro 不见了

别挣扎了&#xff0c;这个项目被官方删了。换别的用吧 别挣扎了&#xff0c;这个项目被官方删了。换别的用吧 别挣扎了&#xff0c;这个项目被官方删了。换别的用吧 别挣扎了&#xff0c;这个项目被官方删了。换别的用吧

关于第二次训练赛

第二次训练赛甚至比第一次还要差&#xff0c;开始做的时候&#xff0c;因为在调并查集的题目&#xff0c;一时忘了比赛开始时间&#xff0c;这又导致了在开始便就输在了起跑线上&#xff0c;接下来看A&#xff0c;20分钟后想到了BFS&#xff0c;不过和p商量后&#xff0c;发现他…

一步获取LeetCode的cookies

登录LeetCode 获取登陆的cookies 浏览器F12。console输入 javascript:document.cookie 打完收工 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布 字数不够csdn不发布

HDU2066:一个人的旅行

Problem Description虽然草儿是个路痴&#xff08;就是在杭电待了一年多&#xff0c;居然还会在校园里迷路的人&#xff0c;汗~),但是草儿仍然很喜欢旅行&#xff0c;因为在旅途中 会遇见很多人&#xff08;白马王子&#xff0c;^0^&#xff09;&#xff0c;很多事&#xff0c;…

win11 vmware 安装Ubuntu 连接xshell

安装 open ssh&#xff1a; sudo apt-get install openssh-server 修改root密码 #sudo passwd root 辑配置文件&#xff0c;允许以 root 用户通过 ssh 登录&#xff1a; sudo vi /etc/ssh/sshd_config 找到&#xff1a;PermitRootLogin prohibit-password禁用 添加&…