单例设计模式(Singleton)
Java设计模式整理第一剑
在我的工作与学习中,对于Java的设计模式还处于只了解部分的阶段,只会简单的写出来,对于为什么要这样设计,这样设计有什么好处和缺点,还谈不上掌握,所以我决定抽出时间,系统性的整理学习,记下自己的学习心得,每天进步一小步。
引言
都说在Java程序员的眼里,世间万物皆对象,从面向对象的角度来看:
- 我们的家里,是不是绝大多数只有一个卫生间呢,因为一个就可以满足我们的日常需求,不需要额外的占用更多的使用面积。
- 当我们在买票的时候,一张票能不能同时被2个人买到使用呢?显然这样不合理,所以对于需要保证每张票唯一的特性,可能涉及到多个人同时操作的情况下,要保证这个对象的唯一性。
- 在天朝,同一时间你最多只能娶一个老婆。。。好吧,这个是开玩笑。。。
通过上面的两个情景,我们可以总结一下单例模式的使用场景以及好处:
一个对象只需要一个就可以满足我们的需求的时候,可以使用单例设计模式,它避免了创建其他实例所占用的资源开销。
对于需要保证一个对象实例的唯一性的时候,我们需要采用单例设计模式。
单例设计模式的实现
通过上面的例子,我们简单地理解了单例设计模式的使用场景与好处,下面我们就在Java中,学习一下单例模式的使用方法。
懒汉式
懒汉式顾名思义,就是比较懒惰,上来的时候没有创建这个类的实例,而是当外部调用这个方法的时候,才会进行判断,如果为空,则创建该类的实例,并返回,不为空的时候,说明已经创建过了,直接返回该实例。
public class Darling {
private Darling() {
super();
}
private static Darling darling = null;
public static Darling getInstance(){
if (null == darling ) {
darling = new Darling();
}
return darling;
}
}
缺点:上面这种写法,并不是线程安全的。为了保证线程安全,我们可以通过下面的写法来保证。
- 通过synchronized关键字来同步方法
public class Darling {
private Darling() {
super();
}
private static Darling darling = null;
public static synchronized Darling getInstance(){
if (null == darling ) {
darling = new Darling();
}
return darling;
}
}
- 双重锁判断
public class Darling {
private Darling() {
super();
}
private static Darling darling = null;
public static Darling getInstance() {
if (null == darling) {
synchronized (Darling.class) {
if (null == darling) {
darling = new Darling();
}
}
}
return darling;
}
}
通过这种形式也保证了线程安全,而且相比上面的写法,这种效率更高,具体体现在:
- 通过同步方法的方式,每次执行这个方法的时候,都需要进行同步。
- 通过双重锁判断,当第一次判断为null的时候,A进入同步代码块内部的同时,进行同步锁,此时即使还未创建完成,B也执行了这个方法,但是因为有锁的存在,B进不来同步代码块,而当A创建完成之后此时darling已经不为null了,B进入了同步代码块里也不会再次创建,保证了线程安全,而且后续再次调用这个方法也不用再次进行同步,效率更高。
饿汉式
之所以成为饿汉式,可以理解为这个人已经饥渴难耐,饥不择食,迫不及待的上来就已经创建好了这个类的实例,而这个类的构造方法是私有的,外部无法通过new关键字来创建,只能通过我们定义的静态的方法拿到Darling对象,同时通过final关键字修饰,保证了它的唯一性,因此通过饿汉式的方法来创建,是线程安全的。
public class Darling {
private Darling() {
}
private static final Darling darling = new Darling();
public static Darling getInstance(){
return darling;
}
}
总结
饿汉式:
是天生线程安全的
懒汉式:
原本不是线程安全的,但是通过synchronized关键字可以保证线程安全,另外双重同步锁判断方式比同步方法效率更高。