转载

设计优化之单例模式设计

论设计模式的重要性:

目前已有多种流行的设计模式,这些都是针对某一种问题的成熟的解决方案。合理使用设计模式,不仅易于理解所设计的系统,也能使系统结构更加合理。以下是几种常见的设计模式及举例。

一、单例模式

简介:单例模式是是设计模式中使用最为普遍的模式之一,它是一种用于对象创建的模式,用来产生一个新的对象,单例,顾名思义就是确保系统中一个类只产生一个实例。

优点:对于一些频繁使用又是重量级的对象,只创建实例一次的这种行为省下了大量创建对象花费的时间,而且节约了系统开销;我们都知道java的垃圾回收,对于“new”的次数减少,减轻了垃圾回收的压力,改善了系统性能。

实例:单例模式的参与者分为单例类和使用者。单例类提供单例的工厂,返回单例;使用者获取并使用单例。

一个简单的单例实现:

public class Singleton{  private static Singleton instance=new Singleton(); private Singleton(){//private访问级别的构造函数 System.out.println("Singleton is created"); }  public static Singleton getInstance(){ return instance; } }

单例类中的private级别构造函数保证了单例不会再系统中其他非单例类代码中被实例化。以上单例实现简单,但是有不足之处,就是不能对instance实例做延迟加载。如果此单例的创建过程缓慢,由于instance变量是static的,因此在JVM加载单例类时单例对象就会被建立。如果此时这个单例类在系统中还扮演其他角色,那么在任何使用这个单例类的地方都会初始化这个单例变量,比如以下代码:

public class Singleton{  private static Singleton instance=new Singleton();  private Singleton(){ System.out.println("Singleton is created"); }  public static Singleton getInstance(){ return instance; }  public static void test(){ System.out.println("just test"); } }

执行Singleton.test();

输出结果:Singleton is created

just test

如此可见,此时并不需要使用单例类但是单例类的确被实例化了。为了解决这个问题,引入了延迟加载机制。

public class LazySingleton(){ private static LazySingleton instance=null;  private LazySingleton(){ System.out.println("LazySingleton is created"); }  public static synchonized LazySingleton getInstance(){ if(instance==null){ instance=new LazySingleton(); } return instance; }  }

以上代码对于instance的初始值为null,确保启动系统时没有额外的负载。在getInstance方法中,对instance实例化时要先进行判断,当instance为null时才对其创建。而且对于getInstance方法要进行方法的同步,否则在多线程环境下,在线程1正在新建单例完成new操作之前线程2发现instance仍然为null时,线程2也将新建单例,就会导致多个实例被创建。

虽然延迟加载功能实现了,但是同步关键字的使用大大增加了耗时。童鞋们可以对以上两种单例创建模式亲自测试一下耗时。

为了解决耗时的问题,又进行了如下的改造:

public class StaticSingleton{  private StaticSingleton{ System.out.println("StaticSingleton is created"); }  private static class SingletonHolder{ private static StaticSingleton instance=new StaticSingleton(); }   public static StaticSingleton getInstance(){ return SingletonHolder.instance; }  }

以上代码中,StaticSingleton被加载时其内部类并不会被初始化,所以instance并不会被实例化,直到getInstance方法被调用时才会加载SingleHolder类,由于实例化是在类加载时完成,故对多线程友好,也不需要同步关键字。

正文到此结束
Loading...