单列模式 [转载]
今天又一次拿起java与模式一书,细看了单列模式
单例模式分为三种:1.饿汉模式,2.懒汉模式,3.登记模式
饿汉模式:在自己被加载时就将自己实例化,即便加载器是静态的
- package singleton;
- public class EagerSingleton
- {
- private static final EagerSingleton eagerSingleton = new EagerSingleton();
- private EagerSingleton(){}
- public static EagerSingleton getInstance()
- {
- return eagerSingleton;
- }
- }
懒汉模式:如果类加载器是静态的,那么懒汉式单例类被加载时不会将自己实例化
- package singleton;
- public class LazySingleton
- {
- private static LazySingleton lazySingleton;
- private LazySingleton(){}
- public synchronized static LazySingleton getInstance()
- {
- if (lazySingleton == null)
- {
- lazySingleton = new LazySingleton();
- }
- return lazySingleton;
- }
- }
登记模式:是为了克服饿汉式单例类及懒汉式单例类均不可继承的缺点而设计的。他的子类实例化的方式只能是懒汉式
- package singleton;
- import java.util.HashMap;
- import java.util.Map;
- //父类
- public class RegisterSingleton
- {
- private static Map m_registry = new HashMap();
- static
- {
- RegisterSingleton registerSingleton = new RegisterSingleton();
- m_registry.put(registerSingleton.getClass().getName(),
- registerSingleton);
- }
- /**
- * 保护的默认构造子
- */
- protected RegisterSingleton()
- {
- }
- public static RegisterSingleton getInstance(String name)
- {
- if (null == name)
- {
- name = "singleton.RegisterSingleton";
- }
- if (m_registry.get(name) == null)
- {
- try
- {
- m_registry.put(name, Class.forName(name).newInstance());
- }
- catch (InstantiationException e)
- {
- e.printStackTrace();
- }
- catch (IllegalAccessException e)
- {
- e.printStackTrace();
- }
- catch (ClassNotFoundException e)
- {
- e.printStackTrace();
- }
- }
- return (RegisterSingleton) m_registry.get(name);
- }
- }
- //子类
- package singleton;
- public class RegisterSingletonChild extends RegisterSingleton
- {
- public RegisterSingletonChild()
- {
- }
- public static RegisterSingletonChild getInstance()
- {
- return (RegisterSingletonChild) RegisterSingleton.getInstance("singleton.RegisterSingletonChild");
- }
- }
由于子类必须允许父类以构造子调用产生实例,因此,它的构造子必须是公开的。这样一来,就等于允许了以这样方式产生实例而不在父类中登记,这是登记式单例模式的一个缺点。
双重检查成例的研究:
是对于懒汉模式的一种改进;因为在第一次调用后,对象已经被实例化,所以再次调用时的同步化就变成了一个不必要的瓶颈,
所以就有了如下的改进:
- package singleton;
- public class LazySingleton
- {
- private static LazySingleton lazySingleton;
- private LazySingleton(){}
- public static LazySingleton getInstance()
- {
- if (lazySingleton == null)
- {
- synchronized(LazySingleton.class)
- {
- if (null == lazySingleton)
- {
- lazySingleton = new LazySingleton();
- }
- }
- }
- return lazySingleton;
- }
- }
但是有说Java语言编译器里面不支持双重检查:具体原因好像是说在java编译器中,LazySingleton类的初始化与lazySingleton变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取lazySingleton引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。
对于这个说法我反正没有验证过。
下面来说说单例的状态:
主要分为有状态的单例类和没有状态的单例类:
一个单例类可以是有状态的,一个有状态的单例对象一般也是可变单例对象。
有状态的可变的单例对象常常当做状态库使用,不如一个单例对象可以持有一个int类型的属性,
用来给一个系统提供一个数值唯一的序列号码,作为某个贩卖系统的账单号码。
当然,一个单例类可以持有一个聚集,从而允许存储多个状态。
一个单例类也可以是没有状态的,仅用作提供工具性函数的对象,既然是为了提供工具性函数,
也就没有必要创建多个实例,因此使用单例模式很适合,一个没有状态的单例类也就是不变单例类
具体可以参见:http://www.iteye.com/topic/959751和http://www.iteye.com/topic/960532