java设计模式(三)—单例模式

来源:互联网 发布:淘宝售后培训ppt 编辑:程序博客网 时间:2024/05/29 11:24

2.概念

     确保一个类只有一个实例,并提供一个全局访问点。


2.作用

    (1) 如下对象只能有一个实例,需要用单例。比方说:线程池,缓存,对话框,处理偏好设置和注册表的对象、日志对象,充当打印机、显卡等设备的驱动程序的对象。

    (2) 为什么不创建一个类,把所有变量和方法都设为静态的,把该类当成一个单例?

         如果类自给自足,不依赖于复杂的初始化,可以这么做。

         但静态初始化的控制权在java手上,当有多个类牵扯其中时,会导致一些微妙的,和初始化顺序有关的bug。

    (3) 为什么不用全局变量?

         全局变量可以提供全局访问,但不能保证只有一个实例。


3.实现方式

    3.1 实现类图

   

    3.2 如果getInstance()的性能对应用程序是不很关键,就什么也不做。(我们认为程序一定是多线程的场景)

         同步getInstance即简单又有效。但同步一个方法会使程序下降100倍,不宜将getInstance()的程序使用在频繁运行的地方。

public class Singleton{  private static Singleton uniqueInstance;  private Singleton{} //构造器是私有的  public static synchronized Singleton getInstance(){        if(uniqueInstance == null){           uniqueInstance = new Singleton();        }        return uniqueInstance;  }}  


    3.3 不用延迟实例化的作法

         如果应用程序总是创建或使用单例,而且在创建和运行时负担不是太重,就可以使用“急切”的方式创建单例。 
        

public class Singleton{  private static Singleton uniqueInstance = new Singleton();  private Singleton{}  public static  Singleton getInstance(){       return uniqueInstance;  }}  


         在静态初始化器中创建单件,上面这段代码保证了线程安全。
         JVM在加载这个类时马上会创建这个唯一的单例。JVM保证在任何线程访问uniqueInstance静态变量之前,一定先创建此实例。

     3.4 用“双重检查加锁”,在getInstance()中使用同步
           volatile关键词确保:当uniqueInstance变量被初始化成Singleton实例时,多个线程可以正确的处理uniqueInstance变量。

public class Singleton{  private volatile static Singleton uniqueInstance;  private Singleton{}  public static  Singleton getInstance(){       if( uniqueInstance == null ){ //检查实例,如果不为空,就进入同步块。            synchronized(Singleton.class){  //只有第一次才彻底执行这里面的代码</span>                if( uniqueInstance == null){  //进入区块后,再检查一次,如果仍是null,才创建实例。(再检查的原因是有可能另一个线程已经进来并创                                               //建了一个实例,这时候就不能再另外创建实例了                   uniqueInstance = new Singleton();                }   }       return  uniqueInstance;  }}  
          注意:双重加锁不适用于1.4及更早版本的java。1.4及更早版本的许多JVM对于volatile关键字的实现会导致双重加锁失效。

 4.注意事项

    (1) 如查程序有多个类加载器,又同时使用了单例模式,请小心。有一个解决办法:自行指定类加载器,并指定同一个类加载器。
    (2) 单例类的构造器是私有的,不能继承。如果将其改成公有的,就可以被实例化多次,就不是真正的单例了。

  








0 0
原创粉丝点击