0.参考资料
1.概述
- Singleton模式中的实例构造器可以设置为 protected 以允许子类派生。
- Singleton模式一般不要支持拷贝构造函数和Clone接口,因为这有可能导致多个对象实例,与Singleton模式的初衷违背。
- 如何实现多线程环境下安全的Singleton?注意对双检查锁的正确实现。
x.问题
x.1 Synchronized锁双重校验法 内存中指令重排问题
双重校验(double check)示例:
public static Singleton getSingleton() {
private static volatile Singleton instance;
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance ;
}
如上,在同步代码块的内部和外部都判断了instance == null,这时因为,可能会有多个线程同时进入到同步代码块外的if判断中,如果在同步代码块内部不进行判空的话,可能会初始化多个实例。
- 问题所在:
- instance = new Singleton(); 并不是原子性的操作。
- new Object(): 汇编后的三句指令:
1.分配内存
2.new 对象
3.把内存地址给引用赋值
- 当instance指向分配地址时,instance不为空<br />但是,2、3步之间,可能会被重排序,造成创建对象顺序变为1-3-2. 若紧接着另外一个线程来调用getInstance,取到的就是状态不正确的对象,程序就会出错。
- 解决方法:
- 使用volatile:防止指令重排,保证有序性.
public class Singleton{
private static volatile Singleton instance;
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance ;
}
}
- 使用volatile:防止指令重排,保证有序性.