J2EE (十) Java中多种方式实现单例模式

 
  1. 简介
    1. “单例”即单一实例从名字上望文生义便可知道该类是作什么的,可见设计模式的名字也是很重要的,让人经过名字就能知道模式的用途,通用性强咱们再命名本身的模式、函数、过程等时候也要遵循这一命名原则,这也成为了编程中一个不成文的规定。
    1. GOF是这样定义的:确保某个类只有一个实例,并且自行实例化并向整个系统提供这个实例。
  1. 特色
    1. 有状态
      1. 一个单例对象能够是有状态的(Stateful),一个有状态的单例对象一般也是可变对象(mutable)
      1. 一个有状态的单例对象能够做为状态库(repositary),好比一个单例对象拥有Int类型的属性,那么它能够提供惟一序列号,供系统使用。
      1. 有状态的单例对象才有可能出现进程同步问题,这有点像函数的传值和传引用,传值不会改变传入参数的值固然就没有影响,只是当一个工具函数来使用。
    1. 无状态
      1. 另外一方面单例也能够是没有状态(stateless),仅看成工具性函数来使用,既然看成工具函数来使用固然也就没有必要再建立多个实例,有一个就够用了,使用单例建立对象很合适。
    1. 不彻底
      1. 构造函数是公开的,正常状况下设置构造函数不公开是为了防止外部类对其进行实例化,若是构造函数公开外部类也不必定会调用,说明它也是一个单例,咱们就称这样的单例为不彻底的单例。
    1. JVM
    1. 一个单例只在一个JVM中运行,当两个类加载器加载同一个类时可能出现两个单例实例。
  1. 举例
    1. 在计算机里面不论是硬件管理仍是软件都有不少用到单例的地方,好比硬件打印机、端口、传真口等在某一个特定时刻只容许一个访问者进行通讯,不然会出现问题
    1. 软件方面回收站、软件系统配置文件的读取都是利用单例实现,由于一个系统中只有一个回收站,回收站本身提供这个实例,
  1. 饿汉与懒汉
    1. 饿汉式
      1. package com.singleton;
        /**
         * Only once instance of the class may be created during the
         * execution of any given program. Instances of this class should
         * be aquired through the getInstance() method. Notice that there
         * are no public constructors for this class.
         */
        public class HungrySingleton {
        		/**
            * @label Creates 
            */
            private static HungrySingleton m_instance = new HungrySingleton();
        	
            private HungrySingleton() { }
        
            public static synchronized  HungrySingleton getInstance()
            {
        	    return m_instance;
        	}
        }

      1. 优缺点
        1. 饿汉单例类在类一加载时就会建立单例对象,并一直存在于内存当中占用了不少存储空间,浪费内存,优势是没有枷锁,执行效率会高一些。
    1. 懒汉式
      1. package com.singleton;
        /**
         * Only once instance of the class may be created during the
         * execution of any given program. Instances of this class should
         * be aquired through the getInstance() method. Notice that there
         * are no public constructors for this class.
         */
        public class lazySingleton {
        		/**
            * @label Creates 
            */
            private static lazySingleton m_instance = null;
        	
            private lazySingleton() { }
        
            public static synchronized   lazySingleton getInstance()
            {
        	    if (m_instance == null)
        	    {
        	        m_instance = new lazySingleton();
        	    }
        	    return m_instance;
        	}
        }

      1. 优缺点
        1. 当对象第一次被引用时建立,比饿汉实例化晚一些所以节省资源,可是懒汉会引发线程不安全,须要枷锁,下降执行效率,。
    1. 那么有没有什么办法克服两个模式的缺点呢?
      1. 在《Java编程思想》中详细介绍了内部类的使用,若是看一看内部类就会知道如何解决这一个问题,内部类是在外部类被调用时才加载,根据这个特色咱们能够把单例中一开始就须要加载的代码移动到内部类里面,这样它的加载顺序就会改变,固然,也就不会再外部类第一次加载时就就行实例化。把饿汉中的初始化代码写在内部类里面,以下:
      1. package com.singleton;
        /**
         * 采用内部类的方式实现单例
         * @author LLS
         *
         */
        public class RegisterSingleton {
        	/*
        	 * 私有构造方法,防止被外类实例化
        	 */
        	private RegisterSingleton(){}
        	/*
        	 * 公开方法
        	 */
        	public static RegisterSingleton getInstance()
        	{
        		return Holder.instance;
        	}
        	/*
        	 * 私有内部类
        	 */
        	private static class Holder
        	{
        		private static final RegisterSingleton instance=new RegisterSingleton();
        	}
        }

      1. 从网上查了查原来这个模式叫作登记式单例,登记式单例的初衷是为了克服单例不能继承的缺点,但这样写彷佛仍是不可以继承,想了想这也算是继承吧。
        1. 由于引入了内部类,内部类能够实现继承类的全部功能,咱们也能够调用内部类,这也至关于继承类的实现。
        1. 登记式单例(采用继承)
          1. 这种登记类经过在父类中Register来实现,即把实例化好的对象放入Map(Key,Value),键值对分别表明类名、类对应的对象。
          2. 在子类中从Map中取出实例,不过,没感受到这种继承有多大好处,若是想继承父类构造函数最少也是protected级别,那么子类呢,得是public或者protected,这样一来子类就能够经过外部new来实例化,没有多大意义了。
  1. Java中应用
    1. 在咱们目前作的系统中饿汉式单利已经能解决问题,建议用饿汉式单例模式。或者使用内部类的单例来管理对象建立。
    1. J2EE中单例模式说简单即简单说难即难,若是涉及到多个JVM以及加载器问题,单例会比较复杂一些,只是目前尚未碰到过这种状况。
相关文章
相关标签/搜索