设计模式之-单例模式(Singleton)

本文深入解析单例模式,包括其定义、目的及多种实现方式,如饿汉式、懒汉式、注册式和序列化式单例。探讨了每种方式的优缺点,特别介绍了Spring框架中注册式单例的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单例模式(Singleton)

保证一个类只有一个实例,并停供一个访问它的全局访问点
Spring中的单例模式完成了后半句话,即提供了全局的访问点BeanFactory,但没有从构造器级别去控制单例,这是因为Spring管理的是是任意的java对象,Spring下默认的Bean均为单例

单例模式为创建型模式,保证了从系统启动到终止,全过程只会产生一个实例

常见的单例模式有饿汉式,懒汉式,注册式,序列化

饿汉式

//饿汉式单例
// 它是在类加载的时候就立即初始化,并且创建单例对象

    //优点:没有加任何的锁、执行效率比较高,
    //在用户体验上来说,比懒汉式更好

    //缺点:类加载的时候就初始化,不管你用还是不用,我都占着空间
    //浪费了内存,有可能占着茅坑不拉屎

    //绝对线程安全,在线程还没出现以前就是实例化了,不可能存在访问安全问题
public class Hungry {

    private Hungry(){}
    //先静态、后动态
    //先属性、后方法
    //先上后下
    private static final Hungry hungry = new Hungry();

    public static Hungry getInstance(){
//        Hungry hungry;

        return  hungry;
    }

}

懒汉式

普通的懒汉式写法是线程不安全

//懒汉式单例

    //在外部需要使用的时候才进行实例化
public class LazyOne {
    private LazyOne(){}


    //静态块,公共内存区域
    private static LazyOne lazy = null;

    public static LazyOne getInstance(){

        //调用方法之前,先判断
        //如果没有初始化,将其进行初始化,并且赋值
        //将该实例缓存好
        if(lazy == null){
            //两个线程都会进入这个if里面
            lazy = new LazyOne();
        }
        //如果已经初始化,直接返回之前已经保存好的结果

        return lazy;

    }

}

安全的懒汉式

//懒汉式单例
    //特点:在外部类被调用的时候内部类才会被加载
    //内部类一定是要在方法调用之前初始化
    //巧妙地避免了线程安全问题

    //这种形式兼顾饿汉式的内存浪费,也兼顾synchronized性能问题
    //完美地屏蔽了这两个缺点
    //史上最牛B的单例模式的实现方式
public class LazyThree {

    private boolean initialized = false;

    //默认使用LazyThree的时候,会先初始化内部类
    //如果没使用的话,内部类是不加载的

    private LazyThree(){

        synchronized (LazyThree.class){
            if(initialized == false){
                initialized = !initialized;
            }else{
                throw new RuntimeException("单例已被侵犯");
            }
        }

    }


    //每一个关键字都不是多余的
    //static 是为了使单例的空间共享
    //保证这个方法不会被重写,重载
    public static final LazyThree getInstance(){
        //在返回结果以前,一定会先加载内部类
        return LazyHolder.LAZY;
    }


    //默认不加载
    private static class LazyHolder{
        private static final LazyThree LAZY = new LazyThree();
    }


}

注册式单例(Spring中就是用的这种)

//spring中的做法,就是这种注册单例模式
public class BeanFactory{
	
	private BeanFactory(){}
	
	//线程安全的
	private static Map<String,Object> ioc = new ConcurrentHashMap<String,Obejct>();
	
	public static Object getBean(String className){
		//如果没有存在ioc中,就以className反射出一个实例
		if(!ioc.containsKey(className)){
			Object obj = null;
			try{
				obj = Class.forName(className).newInstance();
				ioc.put(className,obj);
			}catch(Exception e){
			     e.printStackTrace();
			}
			return obj;
		}else{
			return ioc.get(className);
		}
	}
}

序列化式单例

//反序列化时导致单例破坏
public class Seriable implements Serializable {


    //序列化就是说把内存中的状态通过转换成字节码的形式
    //从而转换一个IO流,写入到其他地方(可以是磁盘、网络IO)
    //内存中状态给永久保存下来了

    //反序列化
    //讲已经持久化的字节码内容,转换为IO流
    //通过IO流的读取,进而将读取的内容转换为Java对象
    //在转换过程中会重新创建对象new


    public  final static Seriable INSTANCE = new Seriable();
    private Seriable(){}

    public static  Seriable getInstance(){
        return INSTANCE;
    }

    private  Object readResolve(){
        return  INSTANCE;
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值