设计模式--单例模式

单例模式的作用:保证整个应用中某个实例中有且仅有一个。

饿汉模式

类的静态成员属于类所有,一旦类加载的时候,instance实例就会被创建。
由于instance对象在类加载时候马上被创建的,所以称之为饿汉。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class HungryMan{
/*
1. 私有化构造方法,不允许外部直接创建对象
2. 创建类的唯一实例
3. 提供一个获取实例的方法
*/
private static HungryMan instance = new HungryMan();
private HungryMan(){
//...doSomething
}
public static HungryMan getInstance(){
return instance;
}
}

懒汉模式

当类加载时候,类的实例并未被创建,只有当调用者第一次使用getInstance时候,类的唯一实例才会被创建。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class LazyMan{
/*
1. 私有化构造方法,不允许外部直接创建对象
2. 声明类的唯一实例
3. 提供一个获取实例的方法
*/
private static LazyMan instance;
private LazyMan(){
//doSomething
}
public static LazyMan getInstance(){
if(instance == null){
instance = new LazyMan();
}
return instance;
}
}

####区别

饿汉模式加载类的时候比较慢,因为要创建instance实例
懒汉模式加载类的时候比较快,因为没有创建instance实例,故在第一次获取实例的时候,会比较慢。

懒汉模式是线程不安全的。
举个例子:
假设开始线程0进入,判断instance为空,在将要创建实例时,cpu切换,线程1又进来了,同样instance为空 创建了实例,这是cpu切换回来到0线程,继续创建实例。
可见,经过分析共创建了两个实例,还谈什么单例。

下面是线程安全的懒汉模式

1
2
3
4
5
6
7
8
9
10
11
12
public static LazyMan getInstance(){
if(instance == null){
//线程0
synchronized(LazyMan.class){
//线程1
if(instance == null){
instance = new LazyMan();
}
}
}
return instance;
}

为什么需要判断两次instance == nulll
假设线程0进来,卡在所示的位置,然后切换cpu,进程1卡在所示位置,那么如果不进行内层的if判断的话,instance又会被创建两次了。