为什么要使用双重校验锁?
在实现单例模式时如果在多线程的情况下
不加校验可能出现的情况:
可能会出现多个实例
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; } }
|