设计模式学习4——单例模式

来源:互联网 发布:燕十八mysql教程视频 编辑:程序博客网 时间:2024/05/17 22:24

参看:http://blog.csdn.net/lovelion/article/details/7420889

一、模式描述

        单例模式(Singletion Pattern):确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例,这个类称为单例类,它提供全局访问的方法。单例模式是一种对象创建型模式。

结构图:

角色:

        Singleton(单例):在单例类的内部实现只生成一个实例,同时它提供一个静态的getInstance()工厂方法,让客户可以访问它的唯一实例。


各种单例模式的实现:

       单例模式必须保证实例在系统中的唯一性,防止创建多个对象,是单例模式的一个重要目标。为了防止创建多个对象,出现了不同的实现方法。

<1>、饿汉式单例

      饿汉式单例在类加载时就创建单例对象,因此后续的使用就不可能创建多个对象。代码如下:

class EagerSingleton {       private static final EagerSingleton instance = new EagerSingleton();       private EagerSingleton() { }         public static EagerSingleton getInstance() {          return instance;       }     }  

<2>懒汉式单例与双重检查锁定(Double-Check Locking)

     懒汉式单例在第一次调用getInstance()方法时实例化,同时对getInstance()方法进行同步控制,从而保证对象的唯一性。

例如:直接用synchronized关键字修饰getinstance()方法,代码如下:

class LazySingleton {       private static LazySingleton instance = null;         private LazySingleton() { }         synchronized public static LazySingleton getInstance() {           if (instance == null) {              instance = new LazySingleton();           }          return instance;       }  }  


    上述代码的问题是每次调用getInstance()方法时都要进行线程锁定判断,在多线程高并发访问环境中,将会导致系统性能大大降低。

     使用双重检查锁定(Double-Check Locking)来改进懒汉式单例,如下:

class LazySingleton {       private volatile static LazySingleton instance = null;         private LazySingleton() { }         public static LazySingleton getInstance() {           //第一重判断          if (instance == null) {              //锁定代码块              synchronized (LazySingleton.class) {                  //第二重判断                  if (instance == null) {                      instance = new LazySingleton(); //创建单例实例                  }              }          }          return instance;       }  } 

注意:静态成员变量instance之前增加修饰符volatile。
<3>、饿汉式与懒汉式的比较

       饿汉式单例类在类被加载时就将自己实例化,它的优点是无须考虑多线程访问问题,系统加载时需要创建对象,加载时间可能会比较长。

       懒汉式单例类在第一次使用是创建,实现了延迟加载。需要多线程机制控制同步,影响系统运行性能。

<4>IoDH单例实现——最好的Java语言单例模式

      通过 Initialization Demand Holder(IoDH)技术,实现延迟加载并且减少同步控制的单例类,(在单例类中增加一个静态内部类,在该内部类中创建单例对象,再将单例对象通过getInstance()方法返回给外部使用)代码如下:

//Initialization on Demand Holder  class Singleton {      private Singleton() {      }            private static class HolderClass {              private final static Singleton instance = new Singleton();      }            public static Singleton getInstance() {          return HolderClass.instance;      }            public static void main(String args[]) {          Singleton s1, s2;               s1 = Singleton.getInstance();          s2 = Singleton.getInstance();          System.out.println(s1==s2);      }  } 
      通过使用IoDH,可以实现延迟加载(因为Singleton类加载时不会加载静态内部类,而是当第一次调用getInstance()时将加载内部类HolderClass,此时会实例化Singleton),又可以保证线程安全(因为仅在静态内部类加载时初始化一次,由Java虚拟机来保证其线程安全性),不影响系统性能,是最好的Java语言单例模式实现方式。


二、模式优缺点

        主要优点:

        <1>、单例模式提供了对唯一实例的受控访问。

        <2>、由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。

        <3>、允许可变数目的实例。基于单例模式我们可以扩展,使用与单例控制相似的方法来获得指定个数的对象实例。

        主要缺点:

         <1>、由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。

         <2>、单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身功能融合在一起。

         <3>、现代面向对象语言提供了自动垃圾回收技术,如果实例化的共享对象长时间不被利用,系统会认为是来及,会自动销毁并回收资源,下次利用时又将重新实例化,导致共享的单例对象状态的丢失。

三、适用场景

        <1>、系统只需要一个实例对象,如系统要求提供一个唯一的序列号生成器或资源管理器,或者需要考虑资源消耗太大而只允许创建一个对象。

        <2>、客户调用类的单个实例只允许使用一个公共访问点,除了该公共访问点,不能通过其他途径访问该实例。


四、案例分析



0 0
原创粉丝点击