设计模式学习笔记——单例模式

ARM 132浏览

单例模式

保证一个类有且只有一个实例,并提供一个访问该实例的全局访问点。要提供一个全局访问点,最常用的办法便是使用类的静态方法,静态方法只能从类而不是从实例中调用。

从理解上还是比较方便理解的,特别在想象了单例模式的实际应用情况后,当一个对象在系统中独一无二,只能有一个的时候,比如一个打印设备,一个进程管理器等等,在这上面,觉得有些类似于多线程锁的概念(所以后面会用到线程同步synchronized)

 

单例模式比较普遍的提到了3种形式(懒汉式,饿汉式,单例注册表)

 

先从最简单的单例模式开始,对照单例模式的特点,要保证该类只有一个实例,所以他的构造方法不可能是public的,必须为private(之后看到在某种需要的情况下,也可能是protect的),但是private构造函数以后,就会造成外界没办法访问,那类也就没有了本身的意义,所以,我们就需要提供一个全局访问点,也就是提供一个外界可以取得该类实例的方法,而同时为了保持实例的唯一性,我们在类的内部嵌入一个静态变量,通过检查该变量,来保证有且仅有一个。

public class Singleton {
	private static Singleton singleton;//创建一个静态变量来保存类的实例
	private Singleton(){}//将构造函数声明为私有,以防止外类访问,导致多次实例化
	public static Singleton getInstance(){//提供一个全局访问点,返回该类的唯一实例
		if(singleton==null){//检查实例是否已经存在,保证唯一性
			singleton=new Singleton();
		}
		return singleton;
	}
}

 

以上是最基本的单例模式实现,但是不用想也知道,肯定有很多缺陷,所以接下来是对他的改进

首先就是提到的线程安全,所以我们在构造方法上加上synchronized

public synchronized static Singleton getInstance(){
	……
}

 这样改进以后就是所谓的懒汉式

 

当然还有另外一个办法保证不会同时2个线程创建了2个实例,就是将实例化提前,在静态变量声明的时候就同时实例化

public class Singleton {
	private static Singleton singleton=new Singleton();//提前实例化
	private Singleton(){}
	public static Singleton getInstance(){
		return singleton;
	}
}

 这个也就是饿汉式单例模式

 

再补充一个看到的双重锁(double-checked locking

public class Singleton{  
	private volatile static Singleton singleton; //注意volatile
    private Singleton(){}         
    public static Singleton getInstance(){      
        if(singleton==null){      
            synchronized(Singleton.class){//双重锁   
               if(singleton==null){      
                  singleton=new Singleton();      
               }   
            }   
        }      
        return singleton;      
    }        
}

从网上看到的情况是,在不同的classloader或者虚拟机JVM下,可能会造成结果的不可预知,所以加了2重锁

然后查了一下volatile关键字,也是为了这个目的,声明为volatile的变量就是可能产生不可预知结果的,volatile保证变量总是从内存中拿去(好像是这样,谁能再补充下,也可能我理解不对

 

最后是单例注册表

单例注册表就是将创建的实例放入到一个注册表中(HashMap),然后每次去注册表中查找实例是否被创建,同样是为了保证唯一性,而这样一个机制,个人理解类似于一个打印机请求的情况,多个打印请求1台打印机,每次只能打印(实例化)一个

 

另外看到还有用反射机制的,没有研究。。

 

这些基本就是我对单例模式的了解,有错误的地方,希望指出