美文网首页JavaSEjava进阶干货Android知识
由单例模式的双判空所展开的思考

由单例模式的双判空所展开的思考

作者: markRao | 来源:发表于2017-11-30 19:16 被阅读249次

相信很多朋友对于单例模式都很熟悉,一般常见的就七八种,百度一大堆,这里聊一下双判空情况下的单例模式。
双判空单例是由单判空所演变而来的,是原来的一些程序员为了提升效率,主要是在JDK版本比较低的时候,锁是比较低效的,双判空从逻辑上可以解决线程的吊起、等待、调度等开销。但是双向判空的单例由于java虚拟机内存分配模型的问题,它并不能实现多线程安全了。


双判空单例模式.png

从设计的逻辑上来说,在锁的外层加上判空可以有效的减少判断锁的开销,但是java实例化从逻辑层面有三个步骤,
1,分配内存空间。
2,对象实例化(即为函数和属性分配内存)。
3,把内存空间的地址指向对象引用。
第二步的操作必须依赖于第一步,因为没有分配内存空间就无法为函数、属性分配内存,但是第三步并不需要依赖于第二步的,因为它只需要内存地址。所以虚拟机在执行过程中会对其实例化的过程进行重新排序,也成为java指令重排序,那么反向思考,虚拟机的设计者为什么要进行指令重排序,总所周知,随着CPU的不断更新迭代,其性能也是大大提升,为了避免在执行内存时造成的CPU空置资源浪费(即慢速内存和高速CPU的不匹配),按照正常的执行顺序,第三步要等待第二步为函数和属性内存分配后才走。
所以虚拟机为了“优化”,进行了指令重排序,即把第三步先于第二步去执行,让逻辑上后面的指令在时间上早与前面的指令,那这样其实就造成了双判空的单例模式实际上得到了一个“半实例化对象”,因为我们的判断条件是if(null == 对象引用),null就是没有指向内存,只要分配了内存空间那该判断条件就不成立。
当然,部分人也很快意识到这个缺陷,给当前的变量加上volatile关键字,就可以解决这个问题,因为这个关键字内部实现可以避免虚拟机的指令重排序,volatile仅仅只是内存的可见性,它和高并发、原子性没有啥关系,只是避免了jvm的指令重排才实现了多线程安全,它的设计初衷就是为了解决锁的低效性,但是现在的锁已经优化很多,几乎可以忽略不计。如果要实现多线程安全,推荐使用静态内部类,这种方式得益于类的加载机制,只会存在一个,另一个则是使用枚举,java的语法糖,简单高效。
记起早先去一家公司面试的时候,还说起这个单例模式,现在想起真是太小太年轻。。。。。。。

相关文章

  • 由单例模式的双判空所展开的思考

    相信很多朋友对于单例模式都很熟悉,一般常见的就七八种,百度一大堆,这里聊一下双判空情况下的单例模式。双判空单例是由...

  • 设计模式 ~ 单例模式

    七种常见的单例模式 1、懒汉式 特点:获取单例时判空即可,线程不安全 2、线程安全的懒汉式 特点:在获取单例的方法...

  • 我要做 Android 之单例模式

    Q:实现单例模式有几种方法?懒汉式中双层锁的目的是什么?两次判空的目的又是什么? 懒汉式(线程不安全) 单例模式最...

  • 单例模式

    单例模式(饿汉式) 单例模式(懒汉式) 解决两种的弊端的单例模式(双锁)

  • kotlin<第四篇>:基础(2)

    一、判空 二、let、with、run、apply、also 三、单例 kotlin 单例实现: 四、静态方法 五...

  • Android单例模式中的双重判空

    mInstance为什么要加volatile? 假设线程A执行了mInstance = new ApiManage...

  • java双检锁构造单例类的问题(jdk1.5前)

    以上代码是典型的java双检锁构造单例模式的代码。看上去两次判空+类锁保证了多线程下的安全,其实不然,这种写法依然...

  • Android设计模式--推荐使用的两种单例模式

    如果不是高并发,出于效率考虑推荐使用如下两种单例模式的写法。 1、两次判空实现单例 优点:资源利用率高,效率高。缺...

  • 单例模式

    单例模式是封装的一种形式,依靠单例模式调用被封装的属性和方法,因为使用单例模式的类无法生成实例(只能引用单例模式所...

  • 设计模式之你真的了解单例模式么?

    问题思考 你知道什么是单例模式么?你能写出一个性能有保障并且安全的单例模式么? 首先我们先明确单例模式的概念,单例...

网友评论

    本文标题:由单例模式的双判空所展开的思考

    本文链接:https://www.haomeiwen.com/subject/fqavbxtx.html