码迷,mamicode.com
首页 > 其他好文 > 详细

单例模式

时间:2015-11-03 00:38:32      阅读:288      评论:0      收藏:0      [点我收藏+]

标签:

单例模式

一 意图

      对于某些类来说,我们其实只需要有一个实例化的对象。比如:注册表,资源管理器,打印机驱动程序等等。

如果我们保证以上的类只有一个实例,并只提供一个统一的访问点的话。系统中便可以统一管理这个对象。

以上类只有一个实例,同时也可以节约系统资源,保证对象信息的一致性。

    我们可以通过单例模式来确保对象的唯一性。

 

 

二 定义

      确保某一个类只有一个实例,只提供一个全局访问点,该类自行实例化并向整个系统提供这个实例,这个类就是单例类

 

    类图:

    技术分享

三 单例模式实现的三个要点

  1. 要保证类只有一个实例,就要禁止类的外部直接使用new来创建对象。把单例类的构造函数的可见性要改为private,只在类的内部使用工厂方法创建实例。
  2. 在单例类中定义一个私有的静态的自己类型的成员变量。
  3. 在单例类中定义一个公开的静态的实例化方法。在实例化方法中判断成员变量 是否实例化。如果没有实例化,则创建一个自身实例。如果已经创建,就直接返回成员变量。

         代码示例(java)

         技术分享

四 饿汉式单例与懒汉式单例

     上述的代码示例,在运行多线程的程序中,可能还是存在一些问题,不能保证对象的唯一性。

例如:有线程1和线程2,同时调用Singleton类的Instance方法。线程1中判断_instance字段为null,对_instance字段进行初始化操作。

     如果Singleton类的初始化信息量大,初始化时间较长。在线程1初始化_instance字段的过程中,假设线程2也调用了Singleton类的Instance方法。如果此时_instance字段还是为null的话,线程2也会对_instance字段进行初始化操作。从而产生了两个Singleton类的实例。Singleton类的实例唯一性无法保证。

     对于多线程的问题,我可以使用饿汉和懒汉单例模式来保证对象的唯一性

 

解决方案:

     1.饿汉式单例

  • 类图
    •   技术分享
  • 代码示例(java)
    • 技术分享  
  • 说明

      当Singleton类加载时,静态变量_instance会被初始化,此时Singleton类的私有构造函数会被调用,单例类的唯一实例就被创建了。

     这样在任何线程调用getInstance()方法之前,Singleton类已经被创建,确保了线程安全。

     2.懒汉式单例

  • 类图

     技术分享

  • 代码示例(java)

     技术分享

  • 说明
    • 懒汉式单例只有在调用了Instance()方法后,才会实例化对象。并不是类一加载的时候,就实例化单例对象。使用延迟加载技术。
    • 在定义静态变量_instance的时,使用了修饰符volatilevolatile修饰符可确保成员变量_instance在多个线程之间信息同步。但是会降低系统运行的效率。
    • 使用关键字synchronized可以对代码进行了锁定,一个线程在实例化对象的时候,另一个线程就必须等待。可以防止多个线程同时实例化Singleton对象。保证了线程的安全,但是锁定代码降低了系统运行的效率。
    • 使用了双重检查锁定,代码示例对_instance是否为null值,进行了两次判断

         第一个_instance == null的判断,是有性能上的好处的。因为只有在第一次_instance == null的时候,才会有对代码进行锁定的操作。_instance不为null的时候,就直接返回了_instance对象了。这样对代码进行锁定的操作只会进行一次了。

         如果不进行双重判断,还是可能将会产生多个单例对象,从而违背单例模式的设计思想。

         假设有线程A和线程B同时调用了Instance()方法,此时_instance为null,线程A和线程B都能通过instance == null的第一次判断。

         由于实现了synchronized加锁机制,线程A和线程B不能同时执行synchronized锁定的代码。

         假设线程A先进入synchronized锁定的代码,实例化Singleton对象。而线程B则处于排队等待状态,它必须等待线程A执行完毕后,才可以进入synchronized锁定的代码中。

         但当线程A实例化完毕后,此时线程B并不知道Singleton对象已经被线程A实例化完毕了。所以必须在synchronized锁定的代码中加上第二个_instance==null的判断。不然线程B将继续创建新的实例,从而导致产生两个单例对象。

   3.饿汉式单例 vs 懒汉式单例

   饿汉式单例

   优点:

       饿汉式单例在类加载的时候就被实例化,无需考虑多线程的问题。代码也不需要锁定,性能上有一定的优势。

   缺点:

       不管系统中是否要引用实例,饿汉式单例在类加载的时候都会创建对象。如果此时系统不需要引用该实例,这样就会造成系统资源的浪费。 

   懒汉式单例

   优点:

       懒汉式单例实现了延迟加载,在类需要被使用时,才会被实例化,不会一直占用系统资源。

   缺点:

       要处理好多线程同时访问的问题,就需要锁定代码,考虑多个线程的同步,这样就会对系统的性能造成一定的影响。

五.总结

    单例模式是一种比较简单的创建型模式,在某种程度上来说它是限制了而不是促进了类的创建。保证类只有一个实例,并只提供一个全局的访问点。在很多应用软件中都有广泛的应用。

 

单例模式

标签:

原文地址:http://www.cnblogs.com/YaoxTao/p/4931895.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!