`
flyingdutchman
  • 浏览: 358405 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论
阅读更多
          单例模式是一个简单的创建者类型的模式,必须保证在系统中最多只能有一个唯一的对象实例,有如下特点:
          1、单例类必须保证最多只有一个实例;
          2、必须由单例类自己创建唯一的实例;
          3、单例类必须给其他所有对象提供其唯一的实例。

          根据创建时间,单例模式又可以分为饥汉式和饱汉式两种,下面通过JAVA代码来分析二者的优缺点。
          饥汉式单例模式:
          /**
           * HungerySingletonPatternTest
           * 饥汉式单例模式
           */
          public class HungerySingletonPatternTest{
              private static final HungerySingletonPatternTest instance = new HungerySingletonPatternTest();
              
              //构造函数声明为private,不能通过new关键字由外部生成实例对象
              private HungerySingletonPatternTest(){
              }

              //只能通过该方法获取类的实例对象
              public static HungerySingletonPatternTest getInstance(){
                     return instance;
              }
          }
          

          饥汉式单例模式优点是简单切线程安全,但是缺点也很明显,在类加载时就要初始化单例类的对象,有可能在整个系统的生命周期内都用不到该单例对象,这样就造成了浪费,特别是该单例类的生成和持有要占很大资源的时候。
          饱汉式单例模式改掉了饥汉式单例模式的缺点,代码如下:
          /**
           * FullSingletonPattern
           * 饱汉式单例模式
           */
          public class FullSingletonPatternTest{
              private static final FullSingletonPatternTest instance = null;
              
              //构造函数声明为private,不能通过new关键字由外部生成实例对象
              private FullSingletonPatternTest(){
              }

              //只能通过该方法获取类的实例对象
              public static synchronized FullSingletonPatternTest getInstance(){
                     if(instance == null){
                         new HungerySingletonPatternTest();
                     }
                     return instance;
              }
          }
          

          饱汉式单例模式虽然改进了饥汉式单例模式的缺点,但是每次在获取单例对象时都要锁(Class Lock),在单线程或没够对单例类对象有竞争的应用场景下,加锁会造成不必要的性能损失。
          对于饱汉式单例模式的缺点,有人提出了所谓的“双重检查锁”的饱汉式单例模式,代码如下:
          /**
           * DoubleCheckerSingletonPatternTest
           * “双重检查锁”饱汉式单例模式
           */
          public class DoubleCheckerSingletonPatternTest{
              private static final DoubleCheckerPatternTest instance = null;
              
              //构造函数声明为private,不能通过new关键字由外部生成实例对象
              private DoubleCheckerSingletonPatternTest(){
              }

              //只能通过该方法获取类的实例对象
              public static DoubleCheckerSingletonPatternTest getInstance(){
                  if(instance == null){
                       synchronized(DoubleCheckerSingletonPatternTest.class){
                           if(instance == null){
                               new DoubleCheckerSingletonPatternTest();
                           }
                       }                         
                   }
                   return instance;
              }
          }
          

          但是“双重检查锁”的饱汉式单例模式,实际上不是线程安全的:由于编译器的优化,允许出现主存和线程工作内存数据不一致问题,这就是“DCL失效”的问题,并不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是总失败。具体原因请参详http://www.ibm.com/developerworks/cn/java/j-dcl.html
          JAVA语言提供内部静态类,我们可以基于内部静态类的特性,改进饱汉式单例模式,提供一种高效而安全的单例模式,代码如下:
           /**
           * StaticInnerClassSingletonPatternTest
           * 基于内部静态类的单例模式
           */
          public class StaticInnerClassSingletonPatternTest{

             private StaticInnerClassSingletonPatternTest{}
              
              //定义一个私有的内部静态类并在其中初始化外部单例对象
              private static class SingletonHolder{
                  static final StaticInnerClassSingletonPatternTest INSTANCE = new StaticInnerClassSingletonPatternTest();
              }                           

              //只能通过该方法获取类的实例对象
              public static StaticInnerClassSingletonPatternTest getInstance(){                 
                   return StaticInnerClassSingletonPatternTest.INSTANCE;
              }
          }
          

          通过静态内部类的方式生成的单例模式,既保证了线程安全的,有保证了延迟加载。
          在JDK发展到JDK 5.0之后,volatile + synchronized可以在保证内存模型的三个特性,即可见性、原子性和顺序性之外,对于被定义为volatile的变量,又禁用了volatile变量的重排序优化,就可以通过如下方式生成的单例模式,既保证安全性又兼顾延迟加载的功能,代码如下:
           /**
           * NewDoubleCheckerSingletonPatternTest
           * volatile + synchronized的“双重检查锁”饱汉式单例模式
           */
          public class NewDoubleCheckerSingletonPatternTest{
              private static volatile NewDoubleCheckerSingletonPatternTest instance = null;
              
              //构造函数声明为private,不能通过new关键字由外部生成实例对象
              private NewDoubleCheckerSingletonPatternTest(){
              }

              //只能通过该方法获取类的实例对象
              public static NewDoubleCheckerSingletonPatternTest getInstance(){
                  if(instance == null){
                       synchronized(NewDoubleCheckerSingletonPatternTest.class){
                           if(instance == null){
                               new DoubleCheckerSingletonPatternTest();
                           }
                       }                         
                   }
                   return instance;
              }
          }
          

         
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics