<iframe align="center" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
已经有众多文章讨论 double-checked locking 模式在 Java 下面无法正常工作,这里先简要的总结一下。
根本原因在于 Java 的 memory model 允许所谓的 out-of-order write ,对于下面的 Java 代码,out-of-order write 可能导致灾难性的结果
public static Singleton getInstance()
{
if (instance == null)
{
synchronized(Singleton.class) { //1
if (instance == null) //2
instance = new Singleton(); //3
}
}
return instance;
}
问题的起因在于语句 //3 ,JIT 所生成的汇编代码所作的事情并不是先生成一个 Singleton 对象,然后将其地址赋予 instance 。相反,它的做法是
1. 先申请一块空内存
2. 将其地址赋予 instance
3. 在 instance 所指的地址之上构建对象
下面的汇编代码提供了证明,说明这不只是一个脑筋急转弯,而是实际发生在 JIT 里面的。代码来自 Peter Haggar 的文章,我只是引用一下。
054D20B0 mov eax,[049388C8] ;load instance ref054D20B5 test eax,eax ;test for null054D20B7 jne 054D20D7054D20B9 mov eax,14C0988h054D20BE call 503EF8F0 ;allocate memory054D20C3 mov [049388C8],eax ;store pointer in ;instance ref. instance ;non-null and ctor ;has not run054D20C8 mov ecx,dword ptr [eax] 054D20CA mov dword ptr [ecx],1 ;inline ctor - inUse=true;054D20D0 mov dword ptr [ecx+4],5 ;inline ctor - val=5;054D20D7 mov ebx,dword ptr ds:[49388C8h]054D20DD jmp 054D20B0其中地址为 054D20BE 的代码正在分配内存,而接下来的一行将其赋予 instance ,这个时候 Singleton 的构造函数根本就还没有被调用。
那么问题在哪里?如果线程调度发生在 instance 已经被赋予一个内存地址,而 Singleton 的构造函数还没有被调用的微妙时刻,那么另一个进入此函数的线程会发觉 instance 已经不为 null ,从而放心大胆的将 instance 返回并使用之。但是这个可怜的线程并不知道此时 instance 还没有被初始化呢!
症结在于:首先,构造一个对象不是原子操作,而是可以被打断的;第二,更重要的,Java 允许在初始化之前就把对象的地址写回,这就是所谓 out-of-order 。
那么,对于 C++ 呢?典型的 C++ double-checked locking 可能是这样的
static Singleton* getInstDC() { if(inst_ == 0) { boost::mutex::scoped_lock l(guard_); if(inst_ == 0) inst_ = new Singleton(); } return inst_; }正如 Java 的行为取决于 JIT 的处理方式,C++ 程序的行为要由编译器来决定。如果某个编译器的处理与 JIT 类似,那么 C++ 程序员也只好对 double-checked locking 说再见。下面是 VC7.1 在 release 配置下生成的代码:
static Singleton* getInstDC() {00401110 mov eax,dword ptr fs:[00000000h] 00401116 push 0FFFFFFFFh 00401118 push offset __ehhandler$?getInstDC@Singleton@@SAPAV1@XZ (4095F8h) 0040111D push eax if(inst_ == 0)0040111E mov eax,dword ptr [Singleton::inst_ (40D000h)] 00401123 mov dword ptr fs:[0],esp 0040112A sub esp,8 0040112D test eax,eax 0040112F jne Singleton::getInstDC+6Eh (40117Eh) { boost::mutex::scoped_lock l(guard_);00401131 mov ecx,offset Singleton::guard_ (40D004h) 00401136 mov dword ptr [esp],offset Singleton::guard_ (40D004h) 0040113D call boost::mutex::do_lock (401340h) 00401142 mov byte ptr [esp+4],1 if(inst_ == 0)00401147 mov eax,dword ptr [Singleton::inst_ (40D000h)] 0040114C test eax,eax 0040114E mov dword ptr [esp+10h],0 00401156 jne Singleton::getInstDC+57h (401167h) inst_ = new Singleton();00401158 push 1 0040115A call operator new (4011A2h) 0040115F add esp,4 00401162 mov dword ptr [Singleton::inst_ (40D000h)],eax }00401167 mov ecx,offset Singleton::guard_ (40D004h) 0040116C mov dword ptr [esp+10h],0FFFFFFFFh 00401174 call boost::mutex::do_unlock (401360h) return inst_;00401179 mov eax,dword ptr [Singleton::inst_ (40D000h)] }0040117E mov ecx,dword ptr [esp+8] 00401182 mov dword ptr fs:[0],ecx 00401189 add esp,14h 0040118C ret 从标记为红色的那一句,我们看到了希望:对 inst_ 的赋值发生在 new 完成之后,这意味着至少在 VC7.1 中,我们尚且可以放心使用 double-checked locking ,尽管它未必具有可移植性。
分享到:
相关推荐
C++ and the Perils of Double-Checked Locking 关于单例模式C++实现的一些问题
C++ and the Perils of Double Checked Locking.zip
C++ 怎么解决 单例模式的线程安全问题
这个小程序涉及到了以下知识点: Java基础知识 队列《数据结构》 单例模式“双检锁/双重校验锁(DCL,即 double-checked locking)”
在做角色权限,通过tree控件展示权限列表的时候,用:default-checked-keys绑定数据,这个属性不能实现双向绑定,只能用于初始化选择状态。如果想双向绑定只能使用组件的方法setCurrentKey来实现。想直接绑定数据来的...
双重检测锁(Double-Checked Locking)实现的Singleton模式在多线程应用中有相当的价值。在ACE的实现中就大量使用ACE_Singleton模板类将普通类转换成具有Singleton行为的类。这种方式很好地消除了一些重复代码臭味,...
本文主要讲解AngularJS ng-checked 指令,在这整理ng-checked 指令的基础知识,并附代码实例,有需要的小伙伴可以参考下
北京火龙果软件工程技术中心意图无论什么时候当临界区中的代码仅仅需要加锁一次,同时当其获取锁的时候必须是线程安全的,可以用DoubleCheckedLocking模式来减少竞争和加锁载荷。动机1、标准的单例。开发正确的有效...
• Chapter 21: The Singleton Pattern and the Double-Checked Locking Pattern • Chapter 22: The Object Pool Pattern • Chapter 23: The Factory Method Pattern • Chapter 24: Summary of Factories (no ...
本篇文章主要介绍了深究AngularJS——ng-checked(回写:带真实案例代码),具有一定的参考价值,感兴趣的小伙伴们可以参考一下
Checked Exception(受检的异常)2---马克-to-win java视频
Checked Exception 和 Unchecked Exception 有什么区别? Throwable 类常用方法有哪些? try-catch-finally 如何使用? finally 中的代码一定会执行吗? 如何使用 try-with-resources 代替try-catch-finally? I/O ...
四色定理的计算机证明,网上有coq平台和定理证明的源代码下载。
checked.css是一款能够制作复选框和单选按钮点击动画的CSS3动画库。它内置23种动画特效,在用户点击单选按钮或复选框时会出现相应的动画效果。
Checked Exception(受检的异常)1---马克-to-win java视频
1.寂寞的Singleton 2. 当Singleton遇见多线程 4.安全发布 6. 讨论的延续 1. JavaWorld章:Double-checked l
多检查奇迹:checked伪类 polyfill(适用于 IE8 及以下)。如何使用包括 jQuery 1.x(与旧 IE 兼容)>= 1.7,然后在 IE 条件注释中包含 poly-checked 脚本: < script src =" //ajax.googleapis....
各种工厂模式 242 第21章 Singleton模式和Double-Checked Locking模式 249 第22章 Object Pool模式 257 第23章 Factory Method模式 267 第24章 工厂模式的总结 272 第八部分 终点与起点 第25章 设计模式回顾:总结与...
北京交通大学期末试卷汇编作业-checked.docx