浅谈单例模式
2019-03-10 11:58:59来源:博客园 阅读 ()
单例模式
看我之前的文章,请戳:
浅谈泛型数组
来一局紧张刺激的吃鸡——浅谈装饰者模式
一起去开心的购物吧——浅谈观察者模式
记一场精彩的篮球比赛——浅谈策略模式
声明:本文为原创,如有转载请注明转载与原作者并提供原文链接,仅为学习交流,本人才识短浅,如有错误,敬请指正
大家好,又见面了,今天继续我们的设计模式之旅,今天的设计模式呢,如标题所示,那就是单例模式。
在我们之前介绍的设计模式中,为了展示这个设计模式的巨大作用,我创建了很多的类来让设计模式工作,而今天的单例模式,告诉大家一个好消息,它只有一个类,听到这里,也许有些人就开始激动了,只有一个类,那么简单的吗,快开始吧。淡定,虽然这个设计模式只有一个类,但是其实他并不是那么容易。
首先我们来看一下单例模式的定义:
单例模式确保一个类只有一个实例,并提供一个全局访问点。
在平时开发中,有的对象我们可能只需要一个,比如线程池,缓存或者日志对象,利用单例模式,我们可以确保一个类只有一个实例,而且可以通过一个方法得到这个唯一的实例。
那么如何实现呢?
众所周知,在Java中我们可以通过new关键字创建一个对象,多次使用new就会创建多个对象,而反应在类中,就是我们每次都会调用类的构造方法。那么,为了让一个类只能有一个实例,如何让多次使用new就会创建多个对象这种行为不再发生呢?
首先我们来看一下经典的单例模式:
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
我们可以看到,Singleton这个类与一般的类最大的不同,就是他的构造方法被我们声明成了一个私有方法,这意味着我们在类的外部无法再通过new操作符执行这个类的构造方法,也就是无法再实例化这个类,那我们去哪里实例化呢,没错,我们在这个类的内部实例化这个对象,可以看到,在类中的getInstance方法中,我们判断了静态变量singleton是否为null,如果为null,则调用构造方法实例化Singleton这个对象,否则,直接返回sington,由于这个singleton只可能在if语句块中被赋值,这就保证了任何情况下都只会有一个singleton出现在上下文中,是吗?
我们来考虑一下,如果有多个线程在执行这段代码,会出现什么样的情形呢?
线程A执行到 if (singleton == null),此时singleton还没有实例化,于是线程A进入了singleton的实例化阶段,但是在他还没实例化对象的时候,CPU调度将线程A挂起,线程B开始执行,此时由于singleton还没有被实例化,所以if语句块线程B也进入了,然后它将singleton实例化并返回,然后线程A继续执行,从之前被挂起的地方开始执行,也实例化了一个singleton,然后返回,此时,我们就会发现在环境中出现了两个singleton实例,这是单例模式所不想看到的情况。
鉴于经典的单例模式有如此的问题,我们必须着手构建一个工作正常的单例模式,事实上,我们有几种比较简单的方式可以帮助我们实现目的。
1. 使用同步方法。
最简单的方法,我们可以在getInstance这个方法上加上关键字“synchronized”,如下:
public class Singleton {
private static Singleton singleton;
private Singleton(){}
public static synchronized Singleton getInstance(){
if (singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
通过添加同步,我们可以避免同时有多个个线程访问该方法,也就可以确保singleton只会被实例化一次。
2. 立即创建实例
我们发现在多线程的情形下,bug出现在我们实例化对象时,如果我们并不在我们需要时实例化而是在一开始就实例化呢?
这就引入了单例模式的两种实例化对象的方式,一种是lazy,我们可以叫他为饱汉模式,还有一直是eager,我们叫他为饿汉模式,事实上,我们的经典的单例模式的实现就是饱汉模式,他意味着,只有当我们主动调用getInstance方法时,对象才会被实例化。
对于另一种饿汉模式,代码如下:
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
我们可以发现,在创建对象引用时我们直接实例化了该对象,而在getInstance方法中我们直接返回了该对象,而且不需要再考虑同步,整体代码显得比饱汉模式更加简洁,那么有同学就会问了,为什么我们不默认使用饿汉模式呢,又简单又省事。
这就涉及到创建对象的成本问题,如果我们始终使用饿汉模式,那么如果要实例化对象的成本很高并且在后面的代码中又没有使用,那么这部分的性能开销就显得很多余,在大部分情况下,我们还是应该秉承着需要时再实例化的思想。
原文链接:https://www.cnblogs.com/MrJR/p/10486938.html
如有疑问请与原作者联系
标签:
版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有
- 设计模式-委派/策略模式 2020-06-09
- 深入理解:设计模式中的七大设计原则 2020-06-07
- 设计模式---类之间的关系知多少 2020-06-07
- 你与面试官所了解的单例模式并不一样! 2020-06-06
- 高手眼中的观察者模式有什么不一样 2020-06-05
IDC资讯: 主机资讯 注册资讯 托管资讯 vps资讯 网站建设
网站运营: 建站经验 策划盈利 搜索优化 网站推广 免费资源
网络编程: Asp.Net编程 Asp编程 Php编程 Xml编程 Access Mssql Mysql 其它
服务器技术: Web服务器 Ftp服务器 Mail服务器 Dns服务器 安全防护
软件技巧: 其它软件 Word Excel Powerpoint Ghost Vista QQ空间 QQ FlashGet 迅雷
网页制作: FrontPages Dreamweaver Javascript css photoshop fireworks Flash