转载:Spring的单例模式底层实现
单例模式也属于创建型模式,所谓单例,顾名思义,所指的就是单个实例,也就是说要保证一个类仅有一个实例。
单例模式有以下的特点:
① 单例类只能有一个实例
② 单例类必须自己创建自己的唯一实例
③ 单例类必须给所有其他对象提供这一实例
单例模式的好处:
1、对于频繁使用的对象,可以省略对象创建的时间
2、由于new操作的次数减少,因而对系统内存的使用频率也会降低,减轻GC压力,缩短GC停顿时间
单例模式主要针对于系统的关键组件和被频繁使用的对象,使用它可以有效改善系统的性能。
单例类必须要有:
1、private访问级别的构造函数,只有这样才能确保单例不会在系统的其他代码内被实例化;
2、instance(实例对象)和getInstance()(获取实例对象的方法)方法必须是static。
按照单例的实现思路,共有三种方式实现单例
1.饿汉模式
public class Singleton1{
private static final Singleton1 instance=new Singleton1();
//私有的默认构造函数
private Singleton1(){}
//静态工厂方法
public static Singleton1 getInstance(){
return instance;
}
}
在这个类被加载时,静态变量instance会被初始化,此时该类的私有构造函数被调用,这时候,单例类的唯一实例就被创建出来了
值得注意的是:由于构造函数是私有的,因此该类不能被继承
2. 懒汉模式
public class Singleton2{
private static final Singleton2 instance=null;
//私有的默认构造函数
private Singleton1(){}
//静态工厂方法
public synchronized static Singleton2 getInstance(){
If(instance==null){
Instance=new Singleton2();
}
Return instance;
}
}
这种写法和第一种的区别在于:
实例并没有直接实例化,而是在静态工厂方法被调用的时候才进行的,而且对静态工厂方法使用了同步化,以
处理多线程并发的环境。
饿汉式单例在自己被加载时就将自己实例化,如果从资源利用效率角度来讲,比懒汉式单例类稍差些。但是从速度和反应时间角度来讲,则比懒汉式要稍好些。但是遗憾的是: 懒汉式单例类也不能被继承。
3. 内部类方式
public class SingleTon03 {
private SingleTon03(){
System.out.println("staticSingle is create");
}
private static class SingleHolder{
private static SingleTon03 instance=new SingleTon03();
}
public static SingleTon03 getInstance(){
return SingleHolder.instance;
}
}
单例模式使用内部类来维护到单例的实例,当SingleTon3被加载时,其内部类并不会被初始化,因此单例类被加载jvm时,不会初始化单例类,而当getInstance()方法被调用时,才加载SingleHolder(内部类),从而初始化instance。
此种方式实例创建是在类加载时完成,因此天生对多线程友好,getInstance方法不必使用同步关键字,是一种比较完善的实现,但是由于构造函数依然是private,无法被继承。
4. 单例注册表模式
import java.util.HashMap;
public class RegSingleton{
static private HashMap registry=new HashMap();
//静态块,在类被加载时自动执行
static{
RegSingleton rs=new RegSingleton();
Registry.put(rs.getClass().getName(),rs);
}
//受保护的默认构造函数,如果为继承关系,则可以调用,克服了单例类不能为继承的缺点
protected RegSingleton(){}
//静态工厂方法,返回此类的唯一实例
public static RegSingleton getInstance(String name){
if(name==null){
name="RegSingleton";
}if(registry.get(name)==null){
try{
registry.put(name,Class.forName(name).newInstance());
}catch(Exception ex){
ex.printStackTrace();
}
}
return (RegSingleton)registry.get(name);
}
}
采用单例注册表方式可以创建可以被继承的单例类,Spring IoC也采用了这种方式生成注入类的单例。
单例类的序列化
一般来说单例类不用于序列化,序列化和反序列化可能会破坏单例,但可以通过重写readReslove的方式加以避免。
public class SingleTon03 {
private SingleTon03(){
System.out.println("staticSingle is create");
}
private static class SingleHolder{
private static SingleTon03 instance=new SingleTon03();
}
public static SingleTon03 getInstance(){
return SingleHolder.instance;
}
private Object readReslove(){
return SingleHolder.instance;
}
}