单例模式的思想,饿汉模式,懒汉模式,双重校验锁

单例模式:

一个类只有一个对象

单例模式包括:饿汉模式和懒汉模式

 

懒汉模式:

   直到要用到实例时,才会去加载。时间换空间

   缺点: 在多线程并发情况下,会产生多个实例化对象,出现线程安全问题

 

uploading.4e448015.gif转存失败重新上传取消

 

 

 

饿汉模式:

     一开始就加载好了,每次用到就直接返回

用空间换时间

uploading.4e448015.gif转存失败重新上传取消

 

总结:

1、单例模式类中的构造是private修饰的,防止外界同过new来创建实例

2、通过public static的方法返回一个实例

3、单例只能有一个实例

4、单例必须自己创建自己的唯一实例

 

单例的优点:

在内存里只存在一个实例,减小了内存的开销,避免对资源的多重占用(比如写文件操作)。

 

单例的缺点:

没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外部怎样来实例化。

 

单例的使用场景:

1、要求生产唯一的序列号

2、WEB中的计数器,不用每次刷新都在数据库里加一次,用单例先缓存起来。

 

单线程下使用单例模式不会出现线程安全问题,但是在多线程环境下,就可能出现。所以就会有双重校验锁

 

uploading.4e448015.gif转存失败重新上传取消

 

 

第一次判断singleton是否为null:

   因为第一次判断是在同步代码块外面进行的,单例模式要求的是只创建一个实例,并且通过getinstances方法返回singleton对象。所以第一次判断是为了防止已经创建了singleton对象的情况下还进入了同步代码块。这一次判断是为了提示效率。

 

第二次判断singleton是否为null

    第二次判断是为了:如果线程a经过第一次判断,它是空的,然后它准备进入同步代码块。这时候线程b获得了时间片,而a还没有经过第二次判断,所以a还没有创建对象,所以singleton依然是空的,b得到时间片后,经过第一次判断,进入同步代码块,也经过第二次判断,然后成功创建了对象。然后a再次获得时间片,它直接进入同步代码块,不会重复进行第一次判断。这时,如果没有第二次判断,a就会直接创建singleton对象,这就不满足我们单例模式的要求,就创建出了两个对象,如果有第二判断,a发现singleton不为空,所以就不能再创建对象。所以第二次判断很有必要的。

 

为什么加volatile关键字? (

   volatile保证了线程的可见性和顺序性。在这里我们主要是利用它的顺序性,保证jvm不会对指令重排序。

   我们都知道创建一个对象不是一步完成的,它分3个步骤。第一步是,获得singleton对象的内存地址,第二步,初始化singleton对象,第三步,把这块内存地址指向引用变量singleton。

   其中第二部初始化操作和第三步指向引用之间是没有依赖关系的,所以在jvm优化程序时,会进行指令重排序。可能在还没有初始化,就让内存地址指向了引用。这时通过getinstance方法获得的对象可能会有错,程序会报异常。所以加上volatile就能保证指令按顺序执行,得到正确的对象。

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值