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

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

双判空单例模式.png

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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ThoughtWorks

TW洞见 | 李光磊:JavaScript语言中五种消除分支的方法

最近开始使用JavaScript。回顾了一下这几天的代码,发现圈复杂度为1。30几个函数40多行,超过两行的函数都很少 (当然那种当做对象来用的函数除外,只说实...

3416
来自专栏编程

java基础思维图解

Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承、指针等概念,因此Java语言具有功能强大和简单易用两个特征。J...

2069
来自专栏CDA数据分析师

不可不知的一点Python陷阱

于易于学习以及快速开发更大更复杂的应用,Python渐渐在计算环境中无处不在。尽管明显的语言清晰度和友好会麻痹软件工程师和系统管理员的警觉性 —— 诱使他们编码...

2968
来自专栏程序员互动联盟

【编程基础第十三讲】代码如何写才最漂亮第二篇

存在问题: 好多小伙伴对编码的格式作用模糊,以为只要完成功能就行,其实这种观点是错误的,一定要重视代码规范,不然你哭的地都找不到。 如何实施: 良好的代码开发习...

2568
来自专栏我的技术专栏

C++设计模式:Template Method

1073
来自专栏java一日一条

有效处理Java异常的三个原则,你知道吗?

在有效使用异常的情况下,异常类型回答了“什么”被抛出,异常堆栈跟踪回答了“在哪“抛出,异常信息回答了“为什么“会抛出,如果你的异常没有回答以上全部问题,那么可能...

1501
来自专栏数据和云

巧用SQL:Oracle中实现split相关方法总结

尚世波 从事数据库方面工作多年,专注于pl/sql开发、数据库设计、优化方面的研究,喜欢挑战 前文回顾:巧用SQL:oracle pl/sql split函...

3835
来自专栏Java技术栈

作为架构师,你必需要搞清楚的概念:POJO、PO、DTO、DAO、BO、VO

POJO、PO、DTO、DAO、BO、VO这些概念作为Java开发来说应该全部或者部分遇到过,作为架构师的你想必更是清楚这些概念在不同场景的应用。 下面我逐一介...

3824
来自专栏Django Scrapy

爬虫的主函数该怎么写

主函数中是将前边写的所有函数汇总,通过多线程,将爬虫稳步有序的进行。 头文件中的那些是之前写好的做引用 用到了多线程技术,在python中,Pool函数是个...

34311
来自专栏java一日一条

Java异常有多慢?

实际上,真正要讨论的问题并不是,“相对‘那些不会发生错误的代码’来说,‘那些以异常形式上报的错误’会有多慢?”,因为你可能也认同“已接受的回答”。相反,真正的问...

3372

扫码关注云+社区