几种单例模式

单例模式

1.作为23种设计模式之一,单例模式的应用还算是比较广泛,无论第三方库还是日常的开发。总能看到单例模式的身影,对于各种不同的实现是有所差异的。在日常开发过程中,看似简单的问题处理到极致还是需要考虑多个方面的因素的,多线程下的安全性、高性能、懒加载。。。

饿汉式

1
2
3
4
5
6
7
8
9
10
11
12
public final class SingleTon {

private static SingleTon INSTANCE = new SingleTon();

private SingleTon() {

}

public static SingleTon getInstance() {
return INSTANCE;
}
}

1.INSTANCE作为类的实例直接初始化,当SingleTon被主动使用时,可以保证在多线程下仅被实例化一次,但是一个如果类的成员属性过多显然比较重。另外不能实现懒加载。

懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class SingleTon {
private static SingleTon INSTANCE = null;

private SingleTon() {

}
public static SingleTon getInstance() {
if (null == INSTANCE) {
INSTANCE = new SingleTon();
}
return INSTANCE;
}
}

1.使用时被创建,避免提前创建。但是存在缺陷,如果在多线程的程序下,当两个线程同时发现INSTANCE == null,导致INSTANCE被实例化了两次,这样就无法保证单例的唯一性。

同步方法+懒汉式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final class SingleTon {
private static SingleTon INSTANCE = null;

private SingleTon() {

}

public static synchronized SingleTon getInstance() {
if (null == INSTANCE) {
INSTANCE = new SingleTon();
}
return INSTANCE;
}
}

1.解决了多线程情况下普通懒汉式单例的可能存在不唯一性,由于synchronized的排他性,作为较重量级的锁,但同时引入了另一个问题–性能较低。

DC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public final class SingleTon {
private static SingleTon INSTANCE = null;
public Object testObj;

private SingleTon() {
//testObj初始化操作
}

public static SingleTon getInstance() {
if (null == INSTANCE) {
synchronized (SingleTon.class) {
if (null == INSTANCE) {
INSTANCE = new SingleTon();
}
}
}
return INSTANCE;
}
}

1.相比于同步方法+懒汉式的单例模式,DoubleCheck解决了首次加载时加锁,当实例存在后,多线程获得实例时则不在通过锁方法,直接获得。解决了性能问题。但是考虑一种情况如上testObj,存在这样一种情况,多个线程调用getInstance()方法时,显然只有一个线程会获得锁而进如初始化的后续操作。由于JVM在实例化时有可能存在指令重排序,也即INSTANCE被先初始化完成而testObj == null。此时如果有另外的线程访问testObj则会出现空指针异常,(INSTANCE已经被实例化完成)。

DC + Volatitle

防止指令重排:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public final class SingleTon {
private volatile static SingleTon INSTANCE = null;
public Object testObj;

private SingleTon() {
//testObj初始化操作
}

public static SingleTon getInstance() {
if (null == INSTANCE) {
synchronized (SingleTon.class) {
if (null == INSTANCE) {
INSTANCE = new SingleTon();
}
}
}
return INSTANCE;
}
}

静态内部类Holder

1
2
3
4
5
6
7
8
9
10
11
12
13
public final class SingleTon {
private SingleTon() {

}

private static class Holder {
private static SingleTon INSTANCE = new SingleTon();
}

public static SingleTon getInstance() {
return Holder.INSTANCE;
}
}

1.借助类的加载机制,SingleTon中没有INSTANCE的实例,而存在于其静态内部类Holder中。当singleton在类的初始化过程中并不会创建SingleTon的实例,而Holder中的静态变量SingleTon(且被实例化),当holder被主动调用时会创建SingleTon的实例。SingleTon的创建过程在编译时期的clinit()中,此为同步方法,保证了可见行,有序性。Holder模式应用比较广泛,没有明显的缺点。

ENUM 枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public final class SingleTon {
private SingleTon() {

}

public static SingleTon getInstance() {
return EnumHolder.INSTANCE.getInstance();
}

private enum EnumHolder {
INSTANCE;
private SingleTon instance;

EnumHolder() {
instance = new SingleTon();
}

private SingleTon getInstance() {
return instance;
}
}
}

1.改进了普通枚举不支持懒加载的缺陷。枚举的优点:-、枚举类型不能被继承;二、线程安全并且只会被实例化一次。

这个功能是摆设,看看就好~~~