双重检查锁实现单例模式的线程安全问题

一、结论 

双重校验锁的单例模式代码如下:

public class Singleton {
  private static Singleton singleton;

  private Singleton() {}

  public static Singleton getSingleton() {
    if (singleton == null) { // 1
      synchronized (Singleton.class) { // 2
        if (singleton == null) { // 3
          singleton = new Singleton(); // 4
        }
      }
    }
    return singleton;
  }
}

假设有两个线程AB同时访问上面这段代码,它并不能保证线程安全。

二、问题说明

  1、指令重排序的简单说明

  重排序是指编译器和处理器为了优化程序性能而对指令序列进行重新排序的一种手段。

  (1)编译器指令重排序

    编译器在不改变程序 执行结果的前提下,可以对程序的执行顺序进行优化重新排序

     (2) 处理器指令重排序

    参考:https://blog.csdn.net/javazejian/article/details/72772461 (处理器指令重排)

  2、 对象创建过程

    分为三步,如下图:

             

我们认为程序应该是按照1、2、3的步骤走下去,但实际上可能不是这样的,这里编译器和处理器可能会对2、3步的执行顺序进行重排序,即先将对象的引用指向内存空间,实际上A线程返回的是没有初始化的对象,然后B线程访问上面这段代码,判断if (singleton == null) { // 1 就为false,它会认为Singleton类已经实例化,问题就出在这里。

  重排序后A 、B线程执行时序图如下:

     

 三、解决方案

  1、不允许对象创建过程中2、3步发生指令重排序 (基于volatile的解决方案)

   即将Singleton声明时加上volatile,volatile关键字可以保证内存可见性和禁止指令重排序,关于volatile参见https://blog.csdn.net/javazejian/article/details/72772461 (volatile内存语义)

    修改后的代码:

    public class Singleton {
      private volatile static Singleton singleton;

      private Singleton() {}

      public static Singleton getSingleton() {
        if (singleton == null) { // 1
          synchronized (Singleton.class) { // 2
            if (singleton == null) { // 3
              singleton = new Singleton(); // 4
            }
          }
        }
        return singleton;
      }
    }

    Singleton属性被加上volatile后,4中对象创建过程的2、3两步在多线程环境下就被禁止重排序,这样就能保证线程安全。

  2、允许对象创建过程中2、3重排序,但不允许其他线程看到这个重排序 (基于类初始化的解决方案)

    JVM在类的初始化阶段,会执行类的初始化。在执行类的初始化期间,JVM会获取一个锁,这个锁可以同步多个线程对同一个类的初始化。基于这个特性修改代码如下:

    public class Singleton {
      private static class SingletonHolder{
        public static Singleton singleton = new Singleton();
      }
      public static Singleton getSingleton(){
        return SingletonHolder.singleton;
      }
    }

        多线程访问上面这段程序的时序图如下:

   

 

 参考资料:

  1、https://blog.csdn.net/javazejian/article/details/72772461

  2、《Java并发编程的艺术》第三章 Java内存模型

    

说明:菜鸟一枚,第一次发技术博客,如有错误或者写的不好的地方欢迎大家指正。

转载于:https://www.cnblogs.com/-Marksman/p/9219274.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/465538.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

摇杆控制方向原理_为工业安全守好”门”!各种方向的控制阀原理图大集合

单向的、换向的....你想了解的方向控制阀都在这里了!方向控制阀门液压阀是用来控制液压系统中油液的流动方向或调节其流量和压力的。方向控制阀作为液压阀的一种,利用流道的更换控制着油液的流动方向。单向型方向控制阀是只允许气流沿一个方向流动的方向…

对于新生代农民工,你有什么想说的?

昨晚上这个新闻很多人转,但是可能很少有人知道他的链接出处,链接来自于http://www.mohrss.gov.cn/SYrlzyhshbzb/jiuye/gzdt/202108/t20210816_420736.html我记得我还在上小学的时候,我们家有干不完的农活,暑假每天都要下田干活&am…

谁是经营之神

—北京维富友携手北京服装学院开展服装ERP沙盘大赛时间4月21日,地点北京服装学院,参加人数35人,参加人员北京维富友软件公司高级讲师、服装学院教师和同学共35人。目的:为了让学生更好的掌握服装企业管理和盈利管控,北…

在Android初次的前期学习中的二个小例子(2)

Hello13:SQLite数据库 一、简述SQLite的概念和主要特性SQLite是一个轻量级的关系型数据库,运算速度快,占用资源少,使用非常方便,支持SQL语法标准和数据库事务原则。相对于SharedPreferences使用文件保存数据,SQLite具有…

access 增加字段 工具_Java效率工具之Lombok

作者:LiWenD正在掘金来源:https://juejin.im/post/5b00517cf265da0ba0636d4b上一篇:数据库查询速度优化之解决技巧还在编写无聊枯燥又难以维护的POJO吗?洁癖者的春天在哪里?请看Lombok!在过往的Java项目中&…

一文读懂 | 进程并发与同步

并发 是指在某一时间段内能够处理多个任务的能力,而 并行 是指同一时间能够处理多个任务的能力。并发和并行看起来很像,但实际上是有区别的,如下图(图片来源于网络):concurrency-parallelism上图的意思是&a…

rust卡领地柜权限_RFID智能医疗耗材柜,上海智能高值耗材柜,国药智能医用耗材柜...

近几年因为我们的医疗改革一直在进步并改革,国家对我们的医疗方面的补助也有了明显的加大投入,与此同时让各种公立私立医院如雨后春笋般层出不穷,各大医院为了在医疗市场占有一席之地,都在各个方面开始想办法提升自己医院的水准。…

刚接触电子时,有过哪些百思不得其解的问题?

青少年时期,刚接触电子时,出于好奇,对这方面的东西也比较关注,但同时也衍生了一些百思不得其解的疑问,比如...01物理书里说大地是导体,那为什么我的小灯珠却不亮!?02初三时学了物理的…

建立管理SQL Server登录帐户

1、打开SQL Server 2005的管理工具,选择以windows身份验证模式登陆。然后右击服务器选择属性。2、在打开的服务器属性页面中,选择“安全性”做如下图设置:3.在windows上新建三个组:ReceptionEmployees,ITEmployees。4、然后在SQL …

c++ doxygen 注释规范_利用Doxygen给C程序生成注释文档

利用Doxygen为C程序生成注释文档一、Doxygen工具的安装利用Doxygen工具生成API帮助文档需要下载安装以下三个软件:(1)Doxygen:可以从一套归档源文件开始,生成HTML格式的在线类浏览器,或离线的LATEX、RTF参考手册。本文中所使用的版…

【2021新版】一线大厂 Go 面试题合集

秋天到了,又到了工程师们躁动不安,蠢蠢欲动的季节~这不,金九银十已然到了家门口,现在后台就有不少人问我:现在外边大厂面试都问啥想去大厂又怕面试挂面试应该怎么准备Go 开发前景如何啥样的后端适合切 Go 技术栈...面试…

python开发【基础二】

基本数据类型: 1、数字 在Python2中,分为整形(int)和长整形(long)。 在Python3中,都是int。 #1、将字符串转换为数字 a "123" v int(a) print(v) print(type(v))#2、当前数字的二进制,至少用几位表示 1位等于8个字节.…

can总线资料

应知识星球的同学要求,整理了一些can总线资料。在公众号后台回复 【can总线】获取资料截图推荐阅读:专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈

Go语言基础之4--流程控制

一、if else语句 1.1 基本语法1 语法1: if condition { //do something } 语法2: if condition { //do something } else { //do something } 语法3: if condition { //do something } else if condition { //do something } else { //do som…

大家都挺难的​

这是昨天小号发的一个推文小时候觉得读书苦 但是现在想想,如果那时候跟现在一样用功 考上北大清华都没问题然后想到跟我家小云聊天的内容,挺有感触的。小云最近在我们小区的业委会上班,业委会在我家旁边,上班就是从这栋楼到另一栋…

android handler封装_Handler都没搞懂,你拿什么去跳槽啊?!

0. 前言做 Android 开发肯定离不开跟 Handler 打交道,它通常被我们用来做主线程与子线程之间的通信工具,而 Handler 作为 Android 中消息机制的重要一员也确实给我们的开发带来了极大的便利。Handler应用之广泛,可以说只要有异步线程与主线程…

做梦也想有一个这样的实验室

从现在开始,努力攒钱,等有钱了,自己也开一个这样的实验室。推荐阅读:专辑|Linux文章汇总专辑|程序人生专辑|C语言我的知识小密圈关注公众号,后台回复「1024」获取学习资料网盘链接。欢迎点赞,关注&#xff…

努力过头了,其实并不好

昨天下午下班的时候,有一个读者朋友找我聊天。我再说下聊天这个事情,如果大家有事情,可以在群里艾特我,因为重要的群我会置顶,置顶的群我会看消息,你在群里艾特我我一定能看到。当然,在群里发一…

jstack 脚本 自动日志_GitLab从安装到全自动化备份一条龙

原文地址[1]欢迎star需求1.在新服务器上安装并搭建好gitlab2.手动自动将旧服务器上的gitlab备份3.手动自动将gitlab备份包scp到新服务器上4.手动自动恢复新服务器上的gitlab备份包5.在新旧服务器上自动删除过期备份包前提1.版本•gitlab-ce是社区版•gitlab-ee是企业版1.方案•…

纪念音视频界前辈-雷霄骅

这是一篇记录文,纪念一位在音视频领域研究的博士雷霄骅。雷霄骅生前是中国传媒大学通信与信息系统博士在读生,于2016年7月17日凌晨猝死在学校主楼五层,10月就将迎来自己26岁的生日。雷霄骅在音视频领域有很深的造诣和贡献,指导了很…