DCL

为什么要使用双重校验锁?
在实现单例模式时如果在多线程的情况下
不加校验可能出现的情况:

可能会出现多个实例

TIME THREAD-A THREAD-B
T1 检查到singleton为空
T2 检查到singleton为空
T3 初始化对象A
T4 返回对象A
T5 初始化对象B
T6 返回对象B
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Singleton {
private static volatile Singleton singleton;

private Singleton() {
}

public static Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}

加了校验不考虑重排序的情况:
可能会访问到一个未初始化完成的对象所以需要加上volatile关键字

TIME THREAD-A THREAD-B
T1 检查到singleton为空
T2 获取锁
T3 检查到singleton为空
T4 为singleton分配内存空间
T5 将singleton指向内存空间
T6 检查到singleton不为空
T7 访问singleton(未初始化)
T8 初始化singleton
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Singleton {
private static Singleton singleton;

private Singleton() {
}

public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}

加上volatile关键字:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Singleton {
private static volatile Singleton singleton;
private Singleton() {
}

public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
查看评论