關于多線程中雙檢查鎖(DCL)初始化發布安全性問題疑惑?

最近在看,有提到雙檢查鎖發布對象的功能.
public MyObject{
private static MyObect obj;
public static MyObect getInstance(){
if(obj == null){
synchronized(MyObect .class){
if(obj == null)
obj = new MyObject();//这里
}
}
return obj;
}
}

有介紹此種方式可能會看看過期值﹐或無效狀態值。

大百度上搜索到以下兩種答案:
第一種﹕

在[url]http://dev.csdn.net/author/axman/4c46d233b388419e9d8b025a3c507b17.html[/url]中提到此種主式(在jdk1.2以上)并不會造成上述異常。

第二種﹕
在[url]http://www.verybc.com/a/hulianwang/2009/1124/8780.html[/url]中提到上種方式會造成上述情況﹐但在解釋時提到[color=red]按照顺序的话,接下来应该运行的步骤是 1) 分配新的Singleton对象的内存 2) 调用Singleton的构造器,初始化成员字段 3) instance被赋为指向新的对象的引用。
前面说过,编译器或处理器都为了升高性能都有估计停止指令的乱序运行,线程一的真正运行步骤估计是1) 分配内存 2) instance指向新对象 3) 初始化新举例。假如线程二在2完成后3运行前被唤醒,它看到了一个的不为null的instance,跳出窍门体走了,带着一个的还没初始化的Singleton对象。[/color]。此段解釋與書中(339頁)提到[color=red]同步仰制了編譯器﹐運行時和硬件對存儲操作的各種方式的重排序(因為obj = new MyObject()是在同步塊中)[/color]

針對引種方式正確的解釋應該為何?

对了,同步不是解决指令重排的,而是volatile关键字

[quote]
Some languages and compilers may provide sufficient facilities to implement functions which address both the compiler reordering and machine reordering issues. In Java version 1.5 (also known as version 5), the volatile keyword is now guaranteed to prevent certain hardware and compiler re-orderings, as part of the new Java Memory Model.
[/quote]

synchronized只能保证java内存模型原子与可见性

[code="java"] private volatile static MyObect obj;
[/code]
这样才对

DCL的缺陷说的是指令乱序

  1. 分配内存
  2. 初始化
  3. 返回new

2和3可能乱序,意思是没有初始化就返回了,返回后再初始化。。

这样出现的问题是,第一个线程还在等待初始化,第二个线程可能获得了对象(obj != null 但是没有初始化),运行的时候因为没有初始化发生异常

此外,拜google大神的程序员才是真的程序员,去找度娘的,都是没上道的程序员

首先,你要知道,内存模型指的是CPU,寄存器,内存等统一抽象的工作内存。现在的计算机,cpu在计算的时候,并不总是从内存读取数据,它的数据读取顺序优先级是:寄存器-高速缓存-内存。线程耗费的是CPU,线程计算的时候,原始的数据来自内存,在计算过程中,有些数据可能被频繁读取,这些数据被存储在寄存器和高速缓存中,当线程计算完后,这些缓存的数据在适当的时候应该写回内存。当个多个线程同时读写某个内存数据时,就会产生多线程并发问题,涉及到三个特性:原子性,有序性,可见性,而实现这个的就是编译期重排和运行时重排序。

对主存的一次访问一般花费硬件的数百次时钟周期。处理器通过缓存(caching)能够从数量级上降低内存延迟的成本这些缓存为了性能重新排列待定内存操作的顺序。也就是说,程序的读写操作不一定会按照它要求处理器的顺序执行

[color=red]
同步仰制了編譯器﹐運行時和硬件對存儲操作的各種方式的重排序(因為obj = new MyObject()是在同步塊中) [/color]