双重检查锁定代码:
//双重检查锁定
public class DoubleCheckedLocking {
private static Instance instance;
public static Instance getInstance() {
if (instance == null) { // Single Checked
synchronized (DoubleCheckedLocking.class) {
if (instance == null) { // Double checked
instance = new Instance();
}
}
}
return instance;
}
}
看起来代码没有没问题
拆分两个线程来执行这段代码:
线程A:
A1、分配对象的内存空间
A2、初始化对象
A3、设置instance指向内存空间
A4、访问instance引用的对象
线程B:
B1、判断instance是否为空
B2、由于instance不为空,线程B将访问instance引用的对象
由于JAVA内存模型intra-thread semantics将确保A2一定会排在A4前面执行。但是重排序会导致 B1判断instance不为空,B2访问instance将会访问到一个还没初始化的对象。
1、基于volatile 可以解决这个问题:
//解决重排序问题
public class DoubleCheckedLocking {
private volatile static Instance instance;
public static Instance getInstance() {
if (instance == null) { // Single Checked
synchronized (DoubleCheckedLocking.class) {
if (instance == null) { // Double checked
instance = new Instance();
}
}
}
return instance;
}
}
2、基于类初始化的解决方案
private static class InstanceHolder {
public static Instance instance = new Instance();
}
public static Instance getInstance() {
return InstanceHolder.instance;
}