一般利用private 与static建立的单例模式
public class Singleton {
private static Singleton sin=new Singleton(); ///直接初始化一个实例对象private Singleton(){ ///private类型的构造函数,保证其他类对象不能直接new一个该对象的实例
}
public static Singleton getSin(){ ///获取实例的public方法
return sin;
}
}
这种方式其中一个缺点是该类加载的时候就会直接new 一个静态对象出来,当系统中这样的类较多时,会使得启动速度变慢 。
我们想办法在第一次使用的时候才初始化第一个该类对象。 线程安全的单例模式:可以在获取方法加上synchronized 使方法同步,然后判断实例为空时就new一个
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static synchronized Singleton getInstance(){ //对获取实例的方法进行同步
if (instance == null)
instance = new Singleton();
return instance;
}
}
但这种直接在方法级别同步粒度较大影响性能,只要将同步范围缩小到if 和new那两行代码就行了,所以还有种双层判空之后加锁方式:
错误写法:(会导致指令重排序,两次判空都是判断instance实例,导致指令重排,多线程下不安全)
public class Singleton {
private static Singleton instance;
private Singleton (){
}
public static Singleton getInstance(){ //对获取实例的方法进行同步
if (instance == null){
synchronized(Singleton.class){
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
有人会问为什么外面还要判断是否为空,其实很多情况都有了一个实例后是不为空的,就无需再走进下面的同步代码块了。
正确写法:第二次判空操作改为判断临时变量temp,防止指令重排,也可以给instance加volatile关键字
public class Singleton {
private static Singleton instance = null;
private Singleton() { }
public static Singleton getInstance() {
if(instance == null) {
synchronzied(Singleton.class) {
Singleton temp = instance;
if(temp == null) {
temp = new Singleton();
instance = temp
}
}
}
return instance;
}
}