单例设计模式

单例模式可以保证系统中,应用该模式的类只有一个对象实例

  • 使用场景

    • spirng的ioc中的对象
    • springboot中的controller,service,dao层中通过@Autowried的依赖注入对象默认都是单例的
  • 分类

    • 懒汉:延迟创建对象
    • 饿汉:提前创建对象
  • 实现步骤

    • 1、私有化构造函数
    • 2、提供获取单例的方法,统一返回对象
  • 接下来就直接进入代码啦,先演示的是懒汉模式

    • 先创建一个类SingletonLazy.class

public class SingletonLazy{
// 实例属性
private static SingletonLazy instance;
	
//私有化实例方法
private SingletonLazy(){};

//提供方法返回对象
public static SingletonLazy getInstance1(){
	if(instance == null){
		instance =  new SingletonLazy();
	}
	return instance;
}

}

  • 上面这种方法在多线程的情况是不安全的,所以我们应该改为线程安全的
public static synchronized SingletonLazy getInstance2(){
	if(instance == null){
		instance =  new SingletonLazy();
	}
	return instance;
}
  • 上面这种方法虽然保证了线程安全,但是在大量线程并发的情况,性能会比较差,所以我们可以尝试先缩小锁的范围。
public static SingletonLazy getInstance3(){
	if(instance == null){
		//锁住当前对象
		synchronized(SingletonLazy.class){
			instance =  new SingletonLazy();
		}
	}
	return instance;
}
  • 但是你以为上面的就是没有问题了吗,其实你仔细分析的话,会发现上面虽然缩小了锁的范围,但是并没有能完全保证线程安全,在极端的情况下,假设abc三个线程同时执行完了 if(isntance == null){这串代码,那么接下来就会发生new了三次对象了。所以我们可以加入双重检查锁定。
public static SingletonLazy getInstance4(){
	if(instance == null){
		//锁住当前对象
		synchronized(SingletonLazy.class){
			if(instance == null){
				instance = new SingletonLazy();
			}
		}
	}
	return instance;
}
  • 到这里,其实看起来就已经很完美了是不?但是不要以为稳了,这里面还是并非安全的,我们知道java中实例化一个对象要经过大概三个步骤
    • 1、申请内存空间
    • 2、在空间内创建对象
    • 3、将对象地址赋值给引用 instance
    • 这里面设计到一个问题–JVM指令重排,不懂的可以先百度,2跟3步骤不是保证顺序的,也就是说可能执行顺序为 1>3>2,这个时候我们的代码就可能会出现new出来的对象是会有问题的(有引用了,但是对象还没真正在空间中创建完成),也就是说其他线程可能用了非完整的对象,这样可能会引发大问题。所以我们这里可以加入volatile关键字,可以禁止指令重排

public static volatile SingletonLazy instance;
public static SingletonLazy getInstance5(){
	if(instance == null){
		synchronized(SingletonLazy.class){
			if(instance == null){
				instance = new SingletonLazy();
			}
		}
	}
	return instance;
}
  • 饿汉模式
  • 创建一个SingletonHungry.class
public class SingletonHungry{
	//饿汉模式当然是直接实例化对象啦
	private static SingletonHungry instance = new SingletonHungry();

	//私有化构造方法
	private SingletonHungry(){};

	//返回对象的方法
	public static getInstance(){
		return instance;
	}

}
  • jdk中有哪些用到了单例模式
  • Runtime类(检查jvm启动相关内存使用等的类)
    在这里插入图片描述

总结:

  • 实战中如何选择

  • 饿汉实现非常简单,也没有安全问题,但是类加载的时候就创建对象,如果是对象非常大和耗时复杂的,就不建议这种方式。其他情况建议采用懒汉模式

  • 更多原创内容,请访问www.渣男.cn

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值