双重检查锁定失败可能性

C语言专升本编程题 湖南省专升本选拔考试,C语言程序设计内部习题 阅读详情

转载之前的话:

双重检查锁失败的原因是:编译器的无序写入(变量等加载顺序不一定)导致instance=new SingleTon(),可能是先为instance分配内存空间,属性设置默认值,也可能是先执行SingleTon的构造方法。这样如果是前者,则另一个线程进入getInstance()方法时,发现instance并不为空,导致会取得构造不完整的instance对系那个。


推荐:当类加载时,就构造单例。

private final staticSingleTon instance = new SingleTon();



双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本:

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton  getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            instance = new Singleton();  
  14.  
  15.        }  
  16.  
  17.        return instance;  
  18.  
  19.     }  
  20.  
  21. }  

上面是最原始的模式,一眼就可以看出,在多线程环境下,可能会产生多个Singleton实例,于是有了其同步的版本:

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public synchronized static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            instance = new Singleton();  
  14.  
  15.        }  
  16.  
  17.        return instance;  
  18.  
  19.     }  
  20.  
  21. }  

在这个版本中,每次调用getInstance都需要取得Singleton.class上的锁,然而该锁只是在开始构建Singleton 对象的时候才是必要的,后续的多线程访问,效率会降低,于是有了接下来的版本:

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            synchronized(Singleton.class) {  
  14.  
  15.               if(instance == null) {  
  16.  
  17.                   instance = new Singleton();  
  18.  
  19.               }  
  20.  
  21.            }  
  22.  
  23.        }  
  24.  
  25.        return instance;  
  26.  
  27.     }  
  28.  
  29. }  

很好的想法!不幸的是,该方案也未能解决问题之根本:

原因在于:初始化Singleton 和 将对象地址写到instance字段 的顺序是不确定的。在某个线程new Singleton()时,在构造方法被调用之前,就为该对象分配了内存空间并将对象的字段设置为默认值。此时就可以将分配的内存地址赋值给instance字段了,然而该对象可能还没有初始化;此时若另外一个线程来调用getInstance,取到的就是状态不正确的对象。

鉴于以上原因,有人可能提出下列解决方案:

  1. public class Singleton {  
  2.  
  3.     private static Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            Singleton temp;  
  14.  
  15.            synchronized(Singleton.class) {  
  16.  
  17.               temp = instance;  
  18.  
  19.               if(temp == null) {  
  20.  
  21.                   synchronized(Singleton.class) {  
  22.  
  23.                      temp = new Singleton();  
  24.  
  25.                   }  
  26.  
  27.                   instance = temp;  
  28.  
  29.               }  
  30.  
  31.            }  
  32.  
  33.        }  
  34.  
  35.        return instance;  
  36.  
  37.     }  
  38.  
  39. }  

该方案将Singleton对象的构造置于最里面的同步块,这种思想是在退出该同步块时设置一个内存屏障,以阻止初始化Singleton 和 将对象地址写到instance字段 的重新排序。

不幸的是,这种想法也是错误的,同步的规则不是这样的。退出监视器(退出同步)的规则是:所以在退出监视器前面的动作都必须在释放监视器之前完成。然而,并没有规定说退出监视器之后的动作不能放到退出监视器之前完成。也就是说同步块里的代码必须在退出同步时完成,而同步块后面的代码则可以被编译器或运行时环境移到同步块中执行。

编译器可以合法的,也是合理的,将instance = temp移动到最里层的同步块内,这样就出现了上个版本同样的问题。

在JDK1.5及其后续版本中,扩充了volatile语义,系统将不允许对 写入一个volatile变量的操作与其之前的任何读写操作 重新排序,也不允许将 读取一个volatile变量的操作与其之后的任何读写操作 重新排序。

在jdk1.5及其后的版本中,可以将instance 设置成volatile以让双重检查锁定生效,如下:

  1. public class Singleton {  
  2.  
  3.     private static volatile Singleton instance = null;  
  4.  
  5.     private Singleton(){}  
  6.  
  7.       
  8.  
  9.     public static Singleton getInstance() {  
  10.  
  11.        if(instance == null) {  
  12.  
  13.            synchronized(Singleton.class) {  
  14.  
  15.               if(instance == null) {  
  16.  
  17.                   instance = new Singleton();  
  18.  
  19.               }  
  20.  
  21.            }  
  22.  
  23.        }  
  24.  
  25.        return instance;  
  26.  
  27.     }  
  28.  
  29. }  

需要注意的是:在JDK1.4以及之前的版本中,该方式仍然有问题。



转自:http://www.xker.com/page/e2011/0422/101056.html

【仿真技巧】Smart Eye Probe在ADS信号仿真中的应用 Smart_Eye_Probe是一个眼探头,允许灵活数量的输入通道,输入通道支持单端或差分信号的混合,并且,可以使用一个共同的时钟信号触发通道的眼图。目前,仅支持瞬态(Transient)和通道(Channel Sim)逐位模式(Bit by bit)模拟,不支持信道统计(Statistical)模式和DDR总线(DDRSim)仿真。 阅读详情

相关推荐

CGNS快速入门到实战(二):VS配置调用CGNS静态链接库

CGNS快速入门到实战这一系列分成三篇文章展开叙述,具体有:(一)CGNS静态链接库编译;(二)VS配置调用CGNS静态链接库;(三)CGNS文件及案例展示。本篇文章重点讲述VS配置调用CGNS静态链接库。

ahang_99的博客 2618

(转)双重检查锁定失败可能性

双重检查锁定失败可能性 双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本: public class Singleton { private static Singleton instance = null; priva...

zhangyeny的专栏 253

ROS2仿真抓取分拣案例,使用myCobot 280机械臂结合ROS2系统搭建机械分拣站

本案例展示了如何利用myCobot 280 urdf模型构建一个对象分类站,并在ROS2 jazzy中完成运动规划。

m0_71627844的博客 2126

“双重检验锁失效”的问题说明

双重检验锁是一个高效的懒加载方法,被广泛引用或应用于多线程环境中。但是,在Java中,如果没有额外的同步,它并不能以独立的方式可靠地工作。当在其它语言上时,比如C++,它依赖于处理器的内存模型,编译器重排序以及编译器和同步库的交互。由于C++并没有对以上内容作出具体说明,所以很难说明在什么情况下双重检验锁会正常运行。在C++中可以显式地使用内存屏障

zhanlanmg的专栏 5325

亚博k210视觉模块与stm32双向通信

【代码】亚博k210视觉模块与stm32双向通信。

w_150831的博客 3246

基于STM32L4XX、HAL库的MP2672GD-0000-Z充电芯片驱动程序设计

CHG_STAT_GPIO_Port, CHG_STAT_Pin, // 这些宏应由 CubeMX 生成在 main.h。

zhusl6688的博客 497

double-checking pattern in java

The "Double-Checked Locking is Broken" Declaration Signed by: David Bacon (IBM Research) Joshua Bloch (Javasoft), Jeff Bogda, Cliff Click (Hotspot JVM project), Paul Haahr, Doug Lea, Tom May, Jan-Wil...

weixin_33857230的博客 261

实验2 存储器设计与实现【计算机组成原理】

实验2 存储器设计与实现【计算机组成原理】

小心星的博客 2399

记录分布式锁双重检测失效问题处理

分布式锁,事务处理

xieshanwu的博客 501

MATLAB 开发项目实例 1000 例专栏之第37例:基于Simulink的无人机飞行控制系统设计

通过上述项目实例,我们成功地使用Simulink设计和仿真了一个无人机的飞行控制系统。这个项目展示了从无人机建模、路径规划、控制器设计到仿真验证的完整流程。Simulink的可视化和模块化特性使得系统的建模和仿真更加直观和高效。

xiaoheshang_123的博客 163

2026从0到1!C#工控机开发实战指南:新手一周就能跑通的完整项目

这篇文章摘要如下: 工业自动化领域工控机开发入门指南,针对零基础开发者提供从环境搭建到项目实战的全流程指导。文章首先解答工控机开发的3个核心问题,比较工控机与普通PC的区别,推荐使用C#作为开发语言。随后详细讲解开发环境配置、四大核心技术栈(通信协议、数据库、UI框架、多线程),并重点演示Modbus TCP通信的实现。最后通过一个完整的温度监控系统项目实战,展示如何用WPF构建实时数据采集界面,包括Modbus通信类编写、数据采集服务实现等关键代码片段。全文采用图解+代码的方式,帮助开发者快速掌握工控系统

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 704

代码质量管理工具:SonarQube常见的问题及正确解决方案

代码质量管理工具:SonarQube常见的问题及正确解决方案 SonarQube 简介 Sonar 是一个用于代码质量管理的开放平台。通过插件机制,Sonar 可以集成不同的测试工具,代码分析工具,以及持续集成工具。 与持续集成工具(例如 Hudson/Jenkins 等)不同,Sonar 并不是简单地把不同的代码检查工具结果(例如 FindBugs,PMD 等)直接显示在 Web 页面上,而是通...

盲目的拾荒者的博客 9655

ROS机器人未知环境自主探索功能包explore_lite最全源码详细解析(二)

本系列文章主要针对ROS机器人常使用的未知环境自主探索功能包explore_lite展开全源码的详细解析,并进行概括总结。 本系列文章共包含六篇文章,前五篇文章主要介绍explore_lite功能包中 explore.cpp、costmap_tools.h、frontier_search.cpp、costmap_client.cpp等源码实现文件中全部函数的详细介绍,第六篇文章进行概括总结,包含自主探索功能包explore_lite的简介,实现未知环境自主探索功能的原理及流程总结,效果演示,使用功能包exp

慕羽★的博客 1648

java单例双检法中双重检查锁定失败可能性

 java单例双检法中双重检查锁定失败可能性     双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本: public class Singleton {        private static Singleton instance = null;        pri

tzl090940126的专栏 774

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

双重检查锁定失败可能性——参照《The "Double-Checked Locking is Broken" Declaration》

双重检查锁定失败可能性——参照《The "Double-Checked Locking is Broken" Declaration》  双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本:   public class Singleton {     private static S

GerryZhu的专栏 5865

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

双重检查锁定失败可能性——参照《The "Double-Checked Locking is Broken" Declaration》...

  双重检查锁定在延迟初始化的单例模式中见得比较多(单例模式实现方式很多,这里为说明双重检查锁定问题,只选取这一种方式),先来看一个版本:   public class Singleton {     private static Singleton instance = null;     private Singleton(){}         public s...

freishlove的博客 198

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

双重检查锁定

http://www.ibm.com/developerworks/cn/java/j-dcl.html 单例创建模式是一个通用的编程习语。和多线程一起使用时,必需使用某种类型的同步。在努力创建更有效的代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。然而,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效。它

applepie1的专栏 2442

双重检查锁定及单例模式

单例创建模式是一个通用的编程习语。和多线程一起使用时,必需使用某种类型的同步。在努力创建更有效的代码时,Java 程序员们创建了双重检查锁定习语,将其和单例创建模式一起使用,从而限制同步代码量。然而,由于一些不太常见的 Java 内存模型细节的原因,并不能保证这个双重检查锁定习语有效。它偶尔会失败,而不是总失败。此外,它失败的原因并不明显,还包含 Java 内存模型的一些隐秘细节。这些事实将导致代

snakeqi的专栏 1961

Java中的双重检查锁定

在本文中,我们将介绍在RxJava中创建Singleton对象的一些技术。 最重要的是,我们将学习Java中的双重检查锁定 。 Java中的Singleton模式是一种创新模式。 随着时间的流逝,人们开始关注Singleton模式的使用和实现。 这是由于单例的实现和使用方式存在一些非常根本的问题所致。 Java中的单例模式具有多种功能,例如: 确保只有一个类实例存在于JVM中...

最佳 Java 编程 507

双重检查锁定和单例模式

编者注 :本文指的是针对Java 5.0进行修改之前的Java内存模型。 有关内存顺序的语句可能不再正确。 但是,在新的内存模型下,再次检查锁定的惯用语仍然无效。 有关Java 5.0中的内存模型的更多信息,请参见“ Java理论和实践:修复Java内存模型” 第1 部分和第2部分 。 Singleton创建模式是常见的编程习惯。 与多个线程一起使用时,必须使用某种类型的同步。 为了创建更...

cusi77914的博客 377

C++和双重检查锁定的危险

C++和双重检查锁定的危险1 简介2 单例模式和多线程3 双重检查锁定模式 多线程只是之后、之前或同时的一件事和另外一个。 1 简介 在Google新闻组或网络上搜索各种设计模式的名称,您肯定会发现最常提到的一种是 Singleton。但是,尝试将 Singleton 付诸实践,您几乎肯定会遇到一个重要的限制:按照传统实现(以及我们在下面解释的),Singleton 不是线程安全的。 已经付出了很多努力来解决这个缺点。最流行的方法之一是其自身的设计模式,即双重检查锁定模式 (DCLP) [13,

weixin_43488529的博客 1195
上一篇: ERROR 1045 (28000): Access denied for user root@localhost (using password: NO)
下一篇: java 字节流与字符流的区别
microsoftq
博客等级 码龄19年 26粉丝 15原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值