我是架构师--设计模式-单例模式

 

   来次面试吧?准备好没,GO!java

 程序员

  1.    问:自我介绍下吧。(开个玩笑。。。往下)请问你用过单例模式吗?什么是单例?  
  2. 答:用过啊,单例模式就是只建立一个实例。  
  3.    问:噢?那是单线程,仍是多线程下都是呢?  
  4. 答:这个类在JVM里就一个实例(这样回答也许会更好)  
  5.    (注:一般面试官,到这里,就会让你写一个单例,固然咱们不,你看这篇文章,就是不让你再网上找其余重复的资料了。)  
  6.    问:说说你用的场景吧  
  7. 答:........  
  8.    问:说说单例的几种类型?或者说什么时候对实例的初始化?  
  9. 答:........  
  10.    问:画过单例的类图吗?会画吗?  
  11. 答:(须要吗?)  
  12.    问:写个单例的实现吧?  

 类名:SingleTon面试

 实例:uniqueInstance 简称ust吧。(这里我插入一句编程规范:起名不要吝惜把实例表明的意思表达清楚,名字可稍微长点,这里就是想偷懒) 编程

实现1:缓存

  
  
  
  
  1. public class Singleton{  
  2.   private final static Singleton ust = new Singleton();  
  3.   private Singleton() {}  
  4.   public static Singleton getInstance(){  
  5.      return ust;  
  6.   }  
  7. }  

注:这里顺便说明一下语法。一般final与static同时出现,习惯让final在前多线程

分析: ide

1. 这里须要加final吗? 是的,由于java反射,能够改变private描述的变量学习

2. 有书里把这种方式称为饿汉单例模式(另外一个种叫懒汉单例),而且已经为人所接受测试

3. 在多线程方面表现出了他优点,不须要担忧方法重复里延时建立带来的原子性(这样说难理解,其实就是出现两个或多个实例)优化

4. 这个,不符合咱们习惯的 用到时再实例化的原则(不过这不要紧。。。)

 看,其实你发现这仍是个不错的单例,那么其实有个最好的实现,最好的实现:

单元素的枚举类型已经成为Singleton的最佳实践

即便面对复杂的序列化或者反射***,绝对防止屡次实例化,还有他的简洁和优雅。

 ----好吧,面试结束了。 其实你对单例的理解仍是不错的,并且你已经获得了最好的答案,有兴趣完全玩转单例吗,继续听我唠叨。


    咱们看看懒汉单例模式:

实现2:

  
  
  
  
  1. public class Singleton{  
  2.     // private final static Singleton ust = null;
  3. // 不应加final,这里明显有偷懒嫌疑,复制上面的例子,又测试不够,之后尽可能避免相似问题。
  4. // 8月15日修正
  5. private static Singleton ust = null;
  6.      private Singleton(){}  
  7.      public staic Singleton getInstance(){  
  8. //建议null==ust的方式,能帮助更快的发现错误。
  9. //部分老程序员的习惯,其实许多IDE会发现些低级错误。  
  10.         if(ust==null){//A  
  11.              ust = new Singleton();//B  
  12.          }  
  13.        return ust;  
  14.      }  
  15. }   

分析:

1. 懒汉模式,作到了须要时建立实例

2. 他遇到了尴尬的问题,由于当两个线程分开运行到A,而后进入了if块,可能就建立了2个实例,草稿的是,你已经初始了一些数据。 

改进一下:

实现3: 

  
  
  
  
  1. public class Singleton{  
  2. private volatile static Singleton ust;  
  3. private Singleton(){}  
  4. public staic Singleton getInstance(){  
  5. synchronized(Singleton.class){  
  6.    if(ust==null){  
  7.     ustnew Singleton();  
  8.    }  
  9.  }  
  10. return ust;  
  11. }  
  12. }  

 分析:

  1. 若是你不理解synchronized 的位置,就不用单例模式这么多写法,不如学习基础

  2. volatile 确保ust被实例化后,多个线程正确处理。他失去了JVM必要的代码优化,若是不是多线程,就不要用

   3. 这个叫作 “双检查加锁”,单例最后一种方式


综合讨论会: 

  
  
  
  
  1. 小明: 单例目前一共谈到懒汉和饿汉两种,还有双检查加锁,最好的应该是单元素的枚举类型  
  2. 小刚: 是的,回答了开头说的几种单例,那么哪些场景应该用单例呢?  
  3. 小明: 我知道,有线程池,缓存,处理偏好设置,注册表,日志对象等等  
  4. 小刚: 对,我对java比较了解,我知道Runtime.getRuntime()。   
  5. C(为吗我叫C):我知道有java.lang.reflect.Proxy类   
  6. 小明:有什么共同点呢,为何用?是遵循对象尽可能少建立原则? 
  7. C:这是什么意思?   
  8. 小刚:这很简单,不过这说法有点问题。由于对象占内存,有要形成垃圾回收,GC的时候JVM但是只干这个麻烦事  
  9. 小明:是啊 
  10. 小刚:我想我知道,某些对象最好只有一个实例,多了会有问题产生。   
  11. C:什么问题?   
  12. 小刚:好比缓存,你从哪一个实例里拿缓存呢?   
  13. 小明:是的啊。。。  

结束讨论会,总结一下吧。不,等等,还要补充两句:
1. 单例模式定义:确保一个只有一个实例,并提供一个全局访问点

2. 若是getInstance()方法对应用程序不会额外负担,或者说影响不大,那写成怎样,其实没太大所谓。可是若是频繁运行,就要仔细考虑,由于一个同步,可能使得执行效率降低100倍

 

继续总结,还差个UML图呢,不妨在上个枚举的例子吧,枚举构造器默认私有吗? 

p_w_picpath 


枚举就算了,是否是默认构造器,本身研究下吧。。。呵呵

这回真总结了:
1. 单例,有懒汉,饿汉,双检查加锁3种常见用法
2. 单例模式,是由于若是多了,会形成数据遗漏等麻烦
3. 最好的单例,单元素的枚举类型

 呵呵,其实,就这些,原本想先写工厂的,由于去面试,遇到某些对单例了解比较浅,解释起来费劲,因而先以单例开篇,请关注下篇工厂模式。

--51CTO首发

相关文章
相关标签/搜索