这是我写的第一篇博客请大家多多支持,如果有写的不对的地方,欢迎大家指正批评!
今天和同事做公交车的时候,同事突然问了一下我单例模式,我说这有什么不会写的,但是同事又问了线程安全的单例模式,我也会写但是一问我问什么是安全的,我突然有点蒙,不知道怎么答,故而查了一下资料记录一下
1 //双重检查锁 2 public final class DoubleCheckedSingleton 3 { 4 private static DoubleCheckedSingletonsingObj = null; 5 6 private DoubleCheckedSingleton(){ 7 } 8 9 public static DoubleCheckedSingleton getSingleInstance(){ 10 if(null == singObj ) { 11 Synchronized(DoubleCheckedSingleton.class){ 12 if(null == singObj) 13 singObj = new DoubleCheckedSingleton(); 14 } 15 } 16 return singObj; 17 } 18 }
至此,上面的写法一方面实现了Lazy-Load,另一个方面也做到了并发度很好的线程安全,一切看上很完美。这是,面试官可能会对你的回答满意的点点头。但是,你此时提出说,其实这种写法还是有问题的!!问题在哪里?假设线程A执行到了第9行,它判断对象为空,于是线程A执行到第12行去初始化这个对象,但初始化是需要耗费时间的,但是这个对象的地址其实已经存在了。此时线程B也执行到了第九行,它判断不为空,于是直接跳到15行得到了这个对象。但是,这个对象还没有被完整的初始化!得到一个没有初始化完全的对象有什么用!!
故而又查了一下静态内部类的实现
public class Singleton {
private static class LazyHolder {private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
单例模式实现方式有好多种,但大部分都会有多线程环境下的问题;使用内部类可以避免这个问题,因为在多线程环境下,jvm对一个类的初始化会做限制,同一时间只会允许一个线程去初始化一个类,这样就从虚拟机层面避免了大部分单例实现的问题