设计模式(五)单例模式

单例模式从名称上就可以理解为:在运行时该类只存在唯一的一个实例。在JAVA中实现单例通常有3种方式:饿汉单例、懒汉单例、IoDH(Initialization Demand Holder)。

饿汉单例:

最简单方便的单例,在类加载时会自动初始化instance,所以调用getInstance方法获取的对象一定是唯一的,也正因如此饿汉单例需要从加载时开始占用资源,对于使用频度较低的类尽量不使用此方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package info.aviraer.design_pattern.singleton_pattern;

/**
* 饿汉单例
* @author Aviraer
*
*/
public class EagerSingleton {

private static EagerSingleton instance = new EagerSingleton();

public static EagerSingleton getInstance(){
return instance;
}

}

懒汉单例:

调用getInstance方法时才实例化对象,相较于饿汉单例更符合资源节约的理念,但是需要使用volatile变量保证单例,而且使用双重检查锁定会影响程序性能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package info.aviraer.design_pattern.singleton_pattern;

/**
* 懒汉单例
* @author Aviraer
*
*/
public class LazySingleton {

/**
* 使用volatile,因为下面的双重判断看似可以保证instance为空时才去new,
* 事实上这样并不能保证第二次判断时instance不为空,原因是对象的创建不是瞬间完成的。
* 关于volatile可以参考https://www.ibm.com/developerworks/cn/java/j-jtp06197.html
*/
private volatile static LazySingleton instance = null;

public static LazySingleton getInstance(){

if (instance == null){
synchronized (LazySingleton.class) {
if (instance == null){
instance = new LazySingleton();
}
}
}
return instance;

}

}

IoDH:

IoDH是结合懒汉和饿汉单例优势的一种单例。在IoDHSingleton加载时并不会实例化HolderClass里的instance,只有当调用getInstance方法时JVM初始化该变量,同时也保证了线程安全。

1
2
3
4
5
6
7
8
9
10
11
12
13
package info.aviraer.design_pattern.singleton_pattern;

public class IoDHSingleton {

private static class HolderClass{
private static final IoDHSingleton instance = new IoDHSingleton();
}

public static IoDHSingleton getInstance(){
return HolderClass.instance;
}

}

 

使用单例模式的优势在于:

1.由于单一实例,所以可以对该实例的访问进行控制

2.实例只创建一次,节约系统资源

3.可扩展为具有限制性的多例,既能提升系统性能又避免资源浪费(类似于连接池和线程池)

 

使用单例模式的劣势在于:

1.没有抽象层,扩展性差

2.职责过重,既是工厂又是产品

3.垃圾回收机制会导致长时间未访问的实例被当作垃圾回收

 

应用场景:

只允许存在一个实例,或创建实例消耗太大。