public final class Singleton {
private Singleton() { }
private static Singleton INSTANCE = null;
public static Singleton getInstance() {
if(INSTANCE == null) { // t2
// 首次访问会同步,而之后的使用没有 synchronized
synchronized(Singleton.class) {
if (INSTANCE == null) { // t1
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}
第一个空判断是:线程已经执行完代码,之后的线程再执行时,不需要创建即进入if判断语句块,直接返回即可。
第二个空判断是:当多个线程同时到达synchronized代码时,由于加锁,只有一个线程进入,当第二个线程进入时,不需要创建,直接返回即可。
看起来没有问题呀!!为什么这么写不行呢?
原因在于INSTANCE = new Singleton();在jvm底层的指令是分开的,先通过构造函数创建对象,再赋值给引用,由于指令重排序,可能是先赋值引用,再创建对象。这就会出现问题:
- 指令重排序后,先赋值引用;
- 第二个线程进来之后,返现不为空,直接返回了,但此时还没有通过构造函数创建对象。
解决方法:使用volatile关键字修饰
public final class Singleton {
private Singleton() { }
private static volatile Singleton INSTANCE = null;
public static Singleton getInstance() {
// 实例没创建,才会进入内部的 synchronized代码块
if (INSTANCE == null) {
synchronized (Singleton.class) { // t2
// 也许有其它线程已经创建实例,所以再判断一次
if (INSTANCE == null) { // t1
INSTANCE = new Singleton();
}
}
}
return INSTANCE;
}
}

1012

被折叠的 条评论
为什么被折叠?



