疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

单例模式(Java代码实现)


 

  单例模式的定义

  单例模式确保类只有一个实例,并且提供一个全局的访问点。

  懒汉式单例模式:延迟实例化,但节省空间

  package com.sxh.singleton;

  public class SingleTon {

  /*

  * volatile关键字确保:当uniqueInstance变量被初始化为SingleTon实例时,多个线程能正确的处理uniqueInstance变量

  * 分析:volatile修饰的成员变量,在每次被线程访问时,都强制性的从共享内存重读该成员的值;

  * 当值发生变化是,强制线程将变化值写入共享内存,任何时候不同线程总是看到你某个成员变量的同一个值

  * */

  private volatile static SingleTon uniqueInstance;//利用一个静态变量来记录SingleTon类的唯一实例

  //其他有用的单件类的数据

  private SingleTon(){} //类外无法访问

  public static SingleTon getInstance(){

  /*

  * 使用”双重检查加锁“,在getInstance中减少使用同步

  * 首先检查是否实例已经创建了,如果尚未创建,才进行同步;只有第一次访问getInstance会同步

  */

  if(uniqueInstance==null){ //确保只有一个实例

  synchronized (SingleTon.class) { //多线程的情况不会出现问题,线程同步问题

  if(uniqueInstance==null){

  uniqueInstance=new SingleTon();//如果我们不需要这个实例,则永远不会产生

  }

  }

  }

  return uniqueInstance;

  }

  //其他有用的单件类的方法,单件类也可以是一般的类,具有一般的数据和方法

  }

  分析:在需要的情况下,才创建唯一的实例对象,是一种延迟实例化的方法。但是要考虑线程同步的问题,会降低执行效率,是一个以时间换空间的方法。

  饿汉式单例模式:急切的创建实例,而不用延迟实例化

  代码如下:

  package com.sxh.singleton;

  public class SingleTon {

  private volatile static SingleTon uniqueInstance=new SingleTon();

  //其他有用的单件类的数据

  private SingleTon(){} //类外无法访问

  public static SingleTon getInstance(){

  return uniqueInstance;

  }

  //其他有用的单件类的方法,单件类也可以是一般的类,具有一般的数据和方法

  }

  分析:对静态变量初始化,JVM在类加载时就马上创建唯一的单例对象;

  不用考虑线程见同步的问题,但可能会浪费空间,是一种以空间换时间的方法。

  IoDH实现单例模式

  实现IoDH时,需要在单例类中增加一个静态内部类,在该内部类中创建单例对象,再将该单例对象通过getInstance()方法给外部使用。

  代码示例如下:

  package com.sxh.singleton;

  public class SingleTon {

  private SingleTon(){} //类外无法访问

  private static class HolderClass{ //静态内部类

  private static final SingleTon uniqueinstance=new SingleTon();

  }

  public static SingleTon getInstance(){

  return HolderClass.uniqueinstance;

  }

  //其他有用的单件类的方法,单件类也可以是一般的类,具有一般的数据和方法

  }

  分析:由于静态单例对象没有作为Singlton的成员变量直接实例化,因此类加载时不会实例化Singleton,第一次调用getInstance()方法时将加载内部类HolderClass,在该内部类中定义一个static类型的静态变量,此时会首先初始化这个成员变量,由Java虚拟机来保证其线程安全性,确保该成员变量只能初始化一次。由于getInstance()方法没有任何线程锁定,因此其性能不会造成任何影响。

  通过使用IoDH,既可以实现延迟加载,又可以保证线程安全,不影响系统性能,因此,IoDH不失为一种最好的Java语言单例模式实现方式。

  单例模式的背景需求:

  在使用注册表对象、日志对象等情况下,这类对象只能有一个实例;如果有多个实例,可能会导致很多问题产生,例如:程序的行为异常、资源使用过量、或者不一致的结果。

  单例模式和全局变量的比较:

  1.首先可以确保只有一个实例被创建,单例模式也给我们一个全局的访问点,和全局变量一样方便。

  2.全局变量和静态变量,在编译时就分配了空间并且初始化;如果将对象赋值给一个全局变量,必须在程序的开始就创建对象;如果对象非常耗费资源,而程序在这次执行过程中又一直没有用到它,就会形成浪费。而使用单例模式,我们可以在需要它的时候才创建对象(延迟实例化)。