《Head First Design Patterns》笔记五:单件模式(Singleton Pattern)

来源:互联网 发布:java选择排序算法代码 编辑:程序博客网 时间:2024/04/28 19:11

概述
   Singleton模式就是1个类只允许唯一一个实例并提供一个全局访问点。比如电脑上的cache,局域网的一台打印机,软件的xml配置文件读写等等只允许有1个实例工作,就需要用到Singleton来实现,我们需要注意的是Singleton在于限制,而不是扩展。
  
需求
    我们现在有一家巧克力工厂,只有1架巧克力熔炉。几条生产线一起工作的话,我们不允许每条生产线都有自己的熔炉,要共用1个熔炉的话,就需要用到Singleton模式了
分析
     Singleton模式可以有几种方式,有个疑问,为什么我们不用全static方法来实现呢,因为这个虽然也能实现全局访问,但没有做到限制。
   ok,我们来逐一分析吧
   1 首先是Singleton的简单实现:如下

 

     这样做到了lazy initialization,但是如果多线程的话我们考虑下这段代码
   if (_instance==null) _instance=new Singleton();
   碰巧多个线程一起访问这里的时候,同时返回true,就会导致产生了多个实例。这可怎么办。
   2 考虑线程安全,代码如下
  

   注意:这里volatile修饰保证字段的访问完全以原始方式访问,而不是靠系统优化(比如说:因为寄存器速度更快,系统优化往往选择调用寄存器内的临时地址,而不是内存中的原始地址,volatile保证了严格访问原始地址)
   调用前先锁定,这样保证了线程安全,但缺点是每次调用都要锁定,浪费了资源。所以可以参考下面的双重判断锁定
   3 双重判断锁定,代码如下

  
     只有初始化的时候才会锁定,这样既保证了线程安全,资源消耗又少,那么我们要问,为什么一定要用lock呢,不用可以实现吗。当然可以。
   4 静态初始化,代码如下

  
     因为类一调用的时候就初始化了实例,所以不存在线程问题,但缺点是没有实现lazy initialization,每次类以调用就自动生成了实例
   5 内类静态初始化,代码如下

 
     哈哈,很好的应用,即实现了lazy initialization,又不存在线程问题。
实现
   下面就是代码实现了,我们选择一种singleton模式来实现ChocolateBoiler类,代码如下
  
   客户端实现,如下:
  
   结果:
  

Fill the Boiler
Fill failed
Boil the chocolate
Boil failed
Drain the chocolate
Fill the Boiler
Boil the chocolate
Drain the chocolate
Drain failed
Fill the Boiler
Boil the chocolate
Drain the chocolate

   注意,由于是多线程,每次结果可能不一样的。

 

下一篇:《Head First Design Patterns》笔记六:命令模式(Command Pattern)

上一篇:《Head First Design Patterns》笔记四:工厂模式(Factory Pattern)