首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >由单例模式的双判空所展开的思考

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

作者头像
萬物並作吾以觀復
发布2018-09-13 17:31:31
5920
发布2018-09-13 17:31:31
举报
文章被收录于专栏:指尖下的Android指尖下的Android

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

双判空单例模式.png

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

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017.11.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档