懒汉模式 是在使用的时候才会生成对象
public class Singleton{
private static Singleton singleton = null;
//私有化构造函数,不能从外部生成
private Singleton(){
}
public static Singleton getSingleton(){
if(singleton == null){
singleton = new Singleton();
}
return singleton;
}
}
但是由于在多线程环境下,但A.B两个线程都进入 if(singleton == null),此时有可能会生成两个对象,所以是线程不安全的
网上一般的解决方案是使用双重同步锁机制,例子如下:
public class singleton{
//私有构造函数
private singleton{
}
//单例对象
private static Singleton instance = null;
//静态的工厂方法
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
虽然加了锁 和双重判断,但是其实这个类是 线程不安全的
原因是:
这个要从cpu的指令开始说起
当我们执行
instance = new Singleton(); 时 要执行什么操作呢
主要分三步
1.分配对象内存空间 memory = allocate()分配对象内存空间
2.ctorInstance()初始化对象
3.instance = memory 设置instance指向刚分配的内存
但是由于存在指令重排的情况(单线程情况下无影响。多线程下会有影响)
由于2 和3 没有顺序的必然关系
也就可能会出现
1.分配对象内存空间 memory = allocate()分配对象内存空间
3.instance = memory 设置instance指向刚分配的内存
2.ctorInstance()初始化对象
此时我们假设有两个线程A和B进入
1.A 先执行了 3.instance = memory 设置instance指向刚分配的内存这个操作,但是还未来得及初始化对象。
2.B 判断 if(instance == null) 时 则会返回true 然后instance, 这时返回值就会出现问题 。
解决方案:
此时使用volatile关键字 则可以解决这个问题 volatile 关键字 有禁止重排序的功能
public class singleton{
//私有构造函数
private singleton{
}
//单例对象
private volatile static Singleton instance = null;
//静态的工厂方法
public static Singleton getInstance(){
if(instance == null){
synchronized(Singleton.class){
if(instance == null){
instance = new Singleton();
}
}
}
return instance;
}
}
此时这个类则是线程安全的,当然如果要使用单例模式,推荐使用的还是枚举方法