设计模式之单件模式

17 views

设计模式真是好东西。单件模式,假设我们只允许一个类只能被实例化一次,例如我们的线程池,我们的临界资源。这些东西只能被实例化一次,也就意味着在我们设计的系统中只能有一个实体。

ok,实例模式就是针对这个问题的设计模式了。其实如果不用单件模式,我们也有很多的解决办法,第一种解决办法就是设计一个全局变量,控制该类实例化的次数,然后记录。这是一种不错的解决办法,但是我们知道全局变量生命周期长,占用内存多,当我们有很多种单件的时候,内存估计会爆炸。
那其他的办法?单件模式

单件模式:确保一个类实例,并提供全局访问点。

最简单的单件模式设计方法:

class SinglePattern{
  private static SinglePattern singlePattern;
   private SinglePattern(){
   }

  public static SinglePattern getInstance(){
      if(singlePattern == NULL){
         singlePattern = new SinglePattern();
      }
    return singlePattern;
  }
}

作为最简单的单件模式设计方案当然是有问题的,上面的方面乍一看解决了只能实例化一次的问题,即将实例化方法设为私有,让其他类访问不到。但是还是存在的问题的,当该类被多个线程调用方法的时候,你会可能返回的不会同一个实例,原因在于只能一个实例,就意味着我们需要对getInstance加一个锁,使在多线程的时候,能够互斥访问,给getInstance方法加上关键字synchronied。 但是其实有另外一种解决,就是把初始化放到变量声明的时候,这样在这个类载入的时候就会初始化实例,而不会在多线程执行getInstance方法的时候发生冲突。
第一种方法:

class SinglePattern{
  private static SinglePattern singlePattern = new SinglePattern();
   private SinglePattern(){
   }

  public static SinglePattern getInstance(){
         return singlePattern;
  }
}

第二种方法:

  private static SinglePattern singlePattern;
   private SinglePattern(){
   }

  public static synchronized SinglePattern getInstance(){
      if(singlePattern == NULL){
         singlePattern = new SinglePattern();
      }
    return singlePattern;
  }
}

然而上述两种方法都有自己的短处,第一种方法就是如果初始化方法需要执行很长的时间的时候,类载入的时间会很黄。第二种方法,synchronzied的代价会很高,程序也会变慢。难道就没有一种优雅的解决办法吗?

有的,如果我们仔细分析一下,我们需要同步的代码是哪些,也就是会产生冲突,使我们生成了两个实例还不知道的代码是哪些,就是这个:

if(singlePattern == NULL){
         singlePattern = new SinglePattern();
      }
多线程单件冲突

在多线程的时候,我们可能同时判断singlePattern为空,然后初始化一个赋值给它,这导致有断时间我们的singlePattern值为A,然后就被另外一个线程赋值成B的现象,这显然违反了我们只能有一个实例的原则。这个有点类似于流水线上的读后写相关。具体图如下所示:

OK, 一个相对比较良好的单件模式的设计方法就设计出来了,如果如下所示:

class SinglePattern{
  private static voliatile SinglePattern singlePattern;
   private SinglePattern(){
   }

  public static SinglePattern getInstance(){
        if(singlePattern == null){
        syschronized(SinglePattern.class){
              if(singlePattern == null){
                    singlePattern = new SinglePattern();
              }
        }
        }
         return singlePattern;
  }
}

voliatile 关键字确保当多线程处理初始化赋值的时候,能够正确的处理singlePattern变量,不会因为被优化指令执行顺序。syschronzed关键字保证了多线程在执行到该代码块的时候能够同步,不会多个线程同时执行该方法。

上述设计的单件模式考虑到了执行速度,多线程执行的时候的同步问题,当整个系统需要改实例的时候,才会被初始化,也保证了效率。显然是单件模式一个良好的用例。

No votes yet.
Please wait...