[菜鸡随笔-2]单例模式

前言:

    上次面试虽然被一家神仙公司坑了,但是在那些很简单的题中还是有一个我不太会的东西,也是之前一直有看见却没有去学习的点。这个点就是【设计模式】中常用的其中一个【单例】。展开了一下后发现还能涉及线程安全的问题..嗯,内容足以写一个博客了。

 

一些辅助阐述的小标注(第二版)

(*    ***)    = 老子拿头来保证就是我是说的这个意思

(?    ***)   = 很有可能不对的理论,我偷懒没做任何验证。是个大胆的假设,可能会坑了你

(@ ***)     = 参考资料中 原文or大义or原文例子

(#   ***)    =  是我用常见的自然语言或例子对原文的翻译、解析

【***】    =  我想让读者注意的名词

(***)         =  我的口水。如果是英文,则是对左侧的名词翻译,对标特定的名词,避免阅读出现歧义。

 

背景介绍-单例模式

    单例模式指的是应用(application)在整个生命周期内,只能存在一个且是同一个对象(往后成为"实例”)。不明白的可以去随便new 两个实例并输出它们的hashCode值。

 

实现的形式

1 饿汉模式(类似静态类)

2 懒汉模式(懒加载)

 

饿汉模式的单例跟【静态类】有很多相似之处,这里就不说静态类了,简单说一下单例的好处。

       1单例可以继承类,实现接口,而静态类不能(可以集成类,但不能集成实例成员)。

       2单例可以被延迟初始化,静态类一般在第一次加载是初始化。

       3单例类可以被集成,他的方法可以被覆写;

       4最后,或许最重要的是,单例类可以被用于多态而无需强迫用户只假定唯一的实例。举个例子,你可能在开始时只写一个配置,但是以后你可能需要支持超过一个配 置集,或者可能需要允许用户从外部从外部文件中加载一个配置对象,或者编写自己的。你的代码不需要关注全局的状态,因此你的代码会更加灵活。

 

饿汉模式

    这就是一个饿汉模式的单例模式。所谓的饿汉模式,即是立即加载。换句话说,就是按以上的设计,在调用者调用 getInstance();得到实例之前,该实例其实早就被初始化了。

    这样的缺点也非常明显,当该单例内容非常多的时候,会占用很多资源,而且这种浪费是有办法可以避免。

 

懒汉模式

   其实就是延迟加载(也就是懒加载LazyLoad),其设计可以让实例在被调用者调用其实例化函数的时候才被创建。这样就避免了内存被浪费。

非常简单就不写备注了。

 

模拟线程安全问题

但是,在多线程的场景里,以上的懒汉模式的设计是非线程安全的。

 

Let me show you

测试代码(开了5个异步线程)

 

测试代码输出。可以看到,每个线程获取的实例的哈希值都不一样。也就是说不是同一个对象。这明显不符合单例模式的初衷。

 

 

 

解决线程安全问题

    其实解决方法很简单如果为了性能不用同步锁(synchronized),那可以加一个判断,判断实例是否已被初始化。但是以上代码还是不能解决问题,why? (模拟业务代码耗时并不是单纯为了拖时间,也模拟了多线程非并行执行的资源调度机制)

    因为我们都知道,线程虽然不是并行执行的,但是譬如有两个线程A和B,A获得执行权进入了IF块后执行权却从线程A给到线程B,B也进入了IF块。so,说到这里都懂了吧?

 

来,真正地解决一下问题。有两种方式(当然不是只有两种,只是我目前只会两种啦..)

 

-NO1

给代码加上类级别或者函数级别的同步锁,这种是最简单同时也是副作用最大的方式(体验在效率)。问题虽然解决了,但是却浪费了很多性能,聪明的你可能已经想到解决办法。我猜猜,"只给实例化对象的代码加同步锁"。Congratulations!你很聪明!但是你或许还漏了点东西,所以才有 NO2

 

-NO 2

这叫DCL双重检查锁机制。

 

这回总算解决问题了,真正地实现了单例模式。

 

结语:

DCL双重检查锁不是最好的解决办法(实际上很多资料都不推荐它,指着DCL来骂..)所以这里就看看单例的内容就好了..这一次没有像上次说的那样写理论的东西,下一次也不会。因为最近想看多一点应用层的知识。

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值