何为单例,就是在一个应用程序中只能有一个实例,就是保证对象只能被new一次。java
懒汉我以为这个名字很形象,就是很懒,因此别的对象加载,它就不加载,你调用个人时候我在加载。比喻hibernate中也有懒模式。ok咱们开始吧面试
一天小明去面试,面试官说,你给我写个单例模式,小明一想这实在太简单了不暇思索很快写出来了以下的单例模式数据库
1 public class Singleton { 2 private static Singleton singleton; 3 public static Singleton getSingleton() 4 { 5 if(singleton==null) 6 { 7 singleton=new Singleton(); 8 } 9 return singleton; 10 } 11 }
而后面试官一看说:你这在高并发的时候有可能会产生多个singleton实例,小明一想怎么会呢,面试官解释说,若是有2个线程T1,T2同时执行,当T1执行到第6行的时候,时间片断到,系统开始让T2执行,执行到第9行,而后T1又开始执行,由于T1已经作过判断此时并不知道singleton已经被实例化,因此singleton此时再次被实例化,这样你系统就有2个singleton对象,那仍是单例吗,小明恍然大悟,这个我能解决,立刻又写出下面这个安全
1 public class Singleton { 2 private static Singleton singleton; 3 4 public synchronized static Singleton getSingleton() 5 { 6 if(singleton==null) 7 { 8 singleton=new Singleton(); 9 } 10 return singleton; 11 }
面试官一看,加上了线程同步,这个时候确实能保证线程安全问题,可是又提出了疑问,若是如今singleton已经被实例化了,若是10个线程同时访问,每次都要等待那么势必形成性能极大的消耗,你有没有别的方案解决问题,小明思考一分钟又写下了下面一段代码并发
1 public class Singleton { 2 private static Singleton singleton; 3 4 public static Singleton getSingleton() 5 { 6 if(singleton==null) 7 { 8 synchronized (Singleton.class) { 9 if(singleton==null) 10 { 11 singleton=new Singleton(); 12 } 13 } 14 } 15 return singleton; 16 }
面试官一看,果然在上面一段代码的基础上提高了很多性能,减小了没必要要的等待,可是仔细一看说你这代码有点问题,并不能保证线程的安全,小明说怎么说呢,而后面试官解释说:若是有T1,T2两个线程,T1线程运行第六行发现singleton==null,就进入第8行,开始对singleton进行实例化,由于实例化中分为三步,第一步为对象开辟内存空间,第二步为对象初始化,第三步是把这个内存地址赋给singleton,可是由于java的内存模式容许无序写入,这样一来会致使第二步和第三步位置调换,那么这样一来就坏了,若是先容许第一步和第三步了,可是此时并无对对象进行初始化,偏偏在此时T2进入了第6行,通过判断singleton不为null,那么就会返回一个没有被初始化的对象。小明听了以为对啊,他说我把内存模式改成不容许无序写入不就好了吗,因而就把代码修改成高并发
1 public class Singleton { 2 private volatile static Singleton singleton;//表示有序写入 3 4 public static Singleton getSingleton() 5 { 6 if(singleton==null) 7 { 8 synchronized (Singleton.class) { 9 if(singleton==null) 10 { 11 singleton=new Singleton(); 12 } 13 } 14 } 15 return singleton; 16 }
面试官又问你知道饿汉模式怎么写的吗,小明一听:哦饿汉,不就是很着急本身立刻进行实例化,生怕本身没法实例化吗,这个简单立刻写了一个饿汉性能
1 public class Singleton { 2 private static Singleton singleton=new Singleton(); 3 public static Singleton getSingleton() 4 { 5 return singleton; 6 } 7 }
小明一看上面的模式,本身突发奇想,饿汉模式着急建立对象,在加载时候消耗性能,而懒汉模式又存在线程安全问题(优化后没有了)能不能结合一下呢,忽然告诉面试官我还有一个比较好的方式来实现,而后他写了下面代码单元测试
1 public class Singleton { 2 private static class SingletonManager{ 3 private final static Singleton SINGLETON=new Singleton(); 4 } 5 public final static Singleton getSingleton() 6 { 7 return SingletonManager.SINGLETON; 8 }
面试官一看,不错不错,既保证了懒加载,同时也保证了线程安全问题。测试
面试官又问小明,那么你知道使用场景吗,小明想了想说,既然在应用程序中只有一个单例,那么势必是用于共享资源,比喻数据库链接池,线程池等均可以用单例模式。优化
面试官继续问:静态类一样也是产生一个对象,和单例具备高度类似你知道他们区别吗,小明回答说
1:面向对象中有三大特性继承,封装和多态,可是静态类是不能够继承的,因此从oo角度来讲静态类并不符合面向对象,他们的类是不能够被覆盖,因此灵活性要比单例差的多
2:因为静态类的特殊他在编译器已经进行实例化了并不能提供懒加载模式
3:对于项目中若是进行单元测试,因为方法不能覆盖一样为测试带来了困难
4:因为静态类在编译器已经都被实例化,因此要比单例性能要快,若是只须要执行一些静态方法这个时候能够采用静态类
原来只是简单的了解单例,概念比较模糊,看了这篇博客,对单例模式有了更清晰的认识。也但愿对大家有所帮助