单例模式中的双检锁写法:
单例模式有很多种写法,有懒汉式和饿汉式,其中叫做双检锁的写法,目测也属于懒汉式,代码大概是这样的:
public class Single{
private volatile static Single single;
private Single(){}
public static Single getInstance(){
if(single==null){
synchronized (Single.class) {
if(single==null){
single=new Single();
}
}
}
return single;
}
}
注意single定义时候的volatile关键字,这个关键字是必要的,可以避免指令重排序导致的问题。
双检锁方法的理论是:只有在对象还没有初始化的时候,才会进入if(single==null)这一行,而且当多个线程同时进入了这一行后,会因为synchronized (Single.class)然后只有一个线程进入该同步代码块,所以代码的初始化只有一次。
但现实是:这种写法在JDK1.5以前并不能保证它会在单处理器或多处理器计算机上顺利运行。
原因:
在JDK1.5以前,因为java内存模型的指令重排序设定,即使有volatile这个关键字,双检锁的方式也会出现问题,会导致在多线程的时候得到还没有完全初始化的对象。
JDK1.5版本对java的内存模型进行了重构,开始使用新的JSR-133内存模型,从此用双检锁方法写的单例就不会再出现以往的问题了(volatile关键字还是需要写)。