单例模式
保证一个类有且只有一个实例,并提供一个访问该实例的全局访问点。要提供一个全局访问点,最常用的办法便是使用类的静态方法,静态方法只能从类而不是从实例中调用。
从理解上还是比较方便理解的,特别在想象了单例模式的实际应用情况后,当一个对象在系统中独一无二,只能有一个的时候,比如一个打印设备,一个进程管理器等等,在这上面,觉得有些类似于多线程锁的概念(所以后面会用到线程同步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台打印机,每次只能打印(实例化)一个
另外看到还有用反射机制的,没有研究。。
这些基本就是我对单例模式的了解,有错误的地方,希望指出