Singleton Pattern -- 不一样的单例模式
Singleton Pattern -- 单例模式
单例模式是用来创建一个只能又一个实例的对象。
单例模式类图如下。

单例模式有两大好处:
(1)对于频繁使用的对象,可以省略创建对象所话费的时间,这对于那些重量级对象而言,是非常可观的一笔系统开销。
(2)由于new操作的次数减少,因而对系统内存的使用频率页会降低,这将减轻GC压力,缩短GC停顿时间。
因此对于系统的关键组件和被频繁使用的对象,使用单例模式便可以有效地改善系统的性能。
这种单例的实现方式非常简单,而且十分可靠,它唯一的不足仅是无法对instance实例做延迟加载。假如单例的创建过程很慢,而由于instance成员变量
是static定义的,因此在JVM加载单例类时,单例对象就会被建立,如果此时,这个单例类在系统中还扮演其他角色,那么在任何使用这个单例类的地方都会
初始化这个单例变量,而不管是否被用到。比如单例类作为String工厂,用于创建一些字符串(该类即用于创建单例Singleton,又用于创建String对象):
单例模式通用代码(饿汉模式):

当使用Singleton.createString()执行任务时,程序输出:

可以看到,虽然此时并没有使用单例类,但它还是被创建出来,这也许是开发人员所不愿意看到的。为了解决这个问题,并以此提高系统在相关函数调用是的
反应速度,就需要引入延时加载机制。
延时单例模式(懒汉模式)

首先,对于静态成员变量instance初始化赋值null,确保系统启动时没有额外的负载;其次,在getInstance()工厂方法中,判断当前单例是否已经存在,
若存在则返回,不存在则再建立单例。这里尤其还要注意,getInstance()方法必须是同步的,否则再多线程的环境下,当一个线程A执行到instance = new
Singleton(),但还没有获得对象(对象初始化时需要时间的),在此同时第二个线程B也在执行,执行到(instance == null)判断,那么线程B判断的结果
也为真。于是继续运行下去,线程A获得了一个对象,线程B也获得了一个对象,在内存中就出现了两个对象!
如下:

开启了5个线程同时完成以上代码的运行,使用第1种类型的单例耗时0ms,而使用LazySingleton,解决了线程安全问题却相对耗时约390ms。性能至
少相差2个数量级。
为了使用延时加载引入的同步关键字反而降低了系统性能,有点得不偿失,我们继续改进:

在这个实现中,单例模式是用来内部类来维护单例的实例,当StaticSingleton被加载时,其内部类并不会被初始化,故可以确保
StaticSingleton类被载入JVM时,不会初始化单例类,而当getInstance()方法被调用时,才会加载SingletonHolder,从而初始化instance。
同时,由于实例的建立是在类加载时完成,故天生对多线程友好,getInstance()方法也不需要使用同步关键字。因此,这种实现方式同时
兼备以上两种实现的优点。
通常情况下,用以上方式实现的单例已经可以确保在系统中只存在唯一实例了。
(现在已经标准的实现了单例模式方式有(单检查锁,双检查锁,枚举),但是如果我们通过反射机制调用,是否会产生多个实例,即破坏了单例模式。)
反射模式,调用方法是不会破坏单例模式,因为反射方法同样受锁&逻辑的保护。
调用构造函数会破坏单例模式,因为构造方法只是private 修饰,防止外部类访问,但是反射方法访问,不受限制。
还有一种破坏次单例模式的方法:对象克隆。这个现象是我在看原型模式时发现。
如果类实现了Clonable接口,那么在得到单例模式对象可以通过clone方法生成单例对象。
所以写单例模式时不要继承或间接继承Clonable接口。
Singleton Pattern -- 不一样的单例模式的更多相关文章
- Net设计模式实例之单例模式( Singleton Pattern)
一.单例模式简介(Brief Introduction) 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯 ...
- 深入浅出设计模式——单例模式(Singleton Pattern)
模式动机对于系统中的某些类来说,只有一个实例很重要,例如,一个系统中可以存在多个打印任务,但是只能有一个正在工作的任务:一个系统只能有一个窗口管理器或文件系统:一个系统只能有一个计时工具或ID(序号) ...
- 浅谈设计模式--单例模式(Singleton Pattern)
题外话:好久没写blog,做知识归纳整理了.本来设计模式就是个坑,各种文章也写烂了.不过,不是自己写的东西,缺少点知识的存在感.目前还没做到光看即能记住,得写.所以准备跳入设计模式这个大坑. 开篇先贡 ...
- 设计模式之单例模式(Singleton Pattern)
单例模式 单例模式(Singleton Pattern)在java中算是最常用的设计模式之一,主要用于控制控制类实例的数量,防止外部实例化或者修改.单例模式在某些场景下可以提高系统运行效率.实现中的主 ...
- 深入设计模式(二)——单例模式(Singleton Pattern)
一.单例模式介绍 单例模式(Singleton Pattern),保证一个类只有一个实例,并提供一个访问它的全局访问点.单例模式因为Singleton封装它的唯一实例,它就可以严格地控制客户怎样访问它 ...
- 乐在其中设计模式(C#) - 单例模式(Singleton Pattern)
原文:乐在其中设计模式(C#) - 单例模式(Singleton Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 单例模式(Singleton Pattern) 作者:weba ...
- C#设计模式之一单例模式(Singleton Pattern)【创建型】
一.引言 看了李建忠老师的讲的设计模式已经有一段时间了(这段时间大概有一年多了),自己还没有写过自己的.有关设计模式的文章.这次想写一些关于设计模式的文章,用自己的理解和代码来写,算是复习一遍 ...
- 【wif系列】C#之单例模式(Singleton Pattern)最佳实践
目录 前言 单例基类 单例提供者 总结 前言 在上一篇译文--<深入理解C#--在C#中实现单例模式>中,对在C#中实现单例模式进行了详细阐述.我们在日常的开发中可以采用解决方案4或解决方 ...
- 【设计模式】单例模式 Singleton Pattern
通常我们在写程序的时候会碰到一个类只允许在整个系统中只存在一个实例(Instance) 的情况, 比如说我们想做一计数器,统计某些接口调用的次数,通常我们的数据库连接也是只期望有一个实例.Windo ...
随机推荐
- gulp常用配置
由于项目中经常会使用到gulp,而每次配置大概都差不多,所以将配置记录一下 项目结构 ├─dist │ ├─assets │ ├─css │ ├─images │ └─js ├─node_module ...
- Linux之centos包管理【rpm】、【yum】、【tar】
rpm包是二进制格式,无需编译安装便可使用,tar包是源码格式,需要编译安装才可使用 rpm包管理: rpm:redhat package manager,红帽的包管理器,其主要的操作参数有如下: - ...
- C++编程指南续
三. 命名规则 比较著名的命名规则当推Microsoft公司的"匈牙利"法,该命名规则的主要思想是"在变量和函数名中加入前缀以增进人们对程序的理解".例如所有的 ...
- 使用 webpack 手动搭建 vue 项目
webpack 是一个前端工程化打包工具,对于前端工程师来说 webpack 是一项十分重要的技能.下面我们就通过搭建一个 vue 项目来学习使用 webpack 主要环境: node v14.15. ...
- 直接插入排序(python实现)
这篇博文用来介绍直接插入排序 直接插入排序基本思想: 每次将一个待排序的记录插入到已经排好序的数据区中,直到全部插入完为止 直接插入排序算法思路: 在直接插入排序中,数据元素分为了有序区和无序区两个部 ...
- 稀疏矩阵三元组表快速转置(C语言实现)
本来准备昨天下午写的,但是因为去参加360众测靶场的考核耽搁了,靶场的题目还是挺基础的. 继续学习吧. 使用黑色墨水在白纸上签名就像由像素点构成的稀疏矩阵.如图4所示. 图4 手写体签名 [问题]请将 ...
- 冲刺Day4
每天举行站立式会议照片: 昨天已完成的工作: 1.登录注册前端与后端的交互 2.订单模块的部分代码 3.用户模块的部分代码 今天计划完成的工作: 成员 任务 高嘉淳 继续完善用户模块的功能 覃泽泰 继 ...
- 手把手教你写DI_3_小白徒手支持 `Singleton` 和 `Scoped` 生命周期
手把手教你写DI_3_小白徒手支持 Singleton 和 Scoped 生命周期 在上一节:手把手教你写DI_2_小白徒手撸构造函数注入 浑身绷带的小白同学:我们继续开展我们的工作,大家都知道 Si ...
- 【学习笔记】浅析平衡树套线段树 & 带插入区间K小值
常见的树套树 一般来说,在嵌套数据结构中,线段树多被作为外层结构使用. 但线段树毕竟是 静态 的结构,导致了一些不便. 下面是一个难以维护的例子: 带插入区间 \(k\) 小值问题 来源:Luogu ...
- 深入理解Java虚拟机(二)——HotSpot对象创建、内存、访问
对象的创建 虚拟机遇到一条字节码new指令时,开始对象创建过程. 首先去检查这个指令的参数是否能在常量池定位到一个类的符号引用: 检查这个符号引用代表的类是否已被加载.解析和初始化,如果没有就必须执行 ...