Double Check Locking -- Java并发the double-check locking broken ?主要解释下内存模型相关的这篇文章ht
Double Check Locking -- Java并发
the double-check locking broken ?主要解释下内存模型相关的这篇文章
http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
?
?
// Broken multithreaded version// "Double-Checked Locking" idiomclass Foo { private Helper helper = null; public Helper getHelper() { if (helper == null) synchronized(this) { if (helper == null) helper = new Helper(); } return helper; } // other functions and members... }?
双检查锁,应用范围很广,很多开源项目,spring,tomcat都能找到。但以上算法是有问题。
出现问题的原因之一:暴露未构造完整的对象。由于编译器或者cpu指令优化,可能导致出现,将未构造完整的Helper对象
引用赋值给 helper字段。假设Helper有个int 属性id = 100。就是说客户端获取到的这个helper,id的值可能是0(没有被正确初始化,即未被构造完整)。解决方法是加volatile。volatile有效防止reorder,从而保证赋值前对象是完整构造过的。
// Broken multithreaded version // "Double-Checked Locking" idiom class Foo { private volatile Helper helper = null; public Helper getHelper() { if (helper == null) synchronized(this) { if (helper == null) helper = malloc(); // other thread can see the reference but not the status of helper, since constructor haven't happened yet. //constructor happens here } return helper; } // other functions and members... }
// Broken multithreaded version // "Double-Checked Locking" idiom class Foo { private volatile Helper helper = null; public Helper getHelper() { if (helper == null) synchronized(this) { if (helper == null) helper = malloc(); // other thread can see the reference but not the status of helper, since constructor haven't happened yet. //constructor happens here } return helper; } // other functions and members... }
JDK5 and later extends the semantics for volatile so that the system will not allow a write of a volatile to be reordered with respect to any previous read or write, and a read of a volatile cannot be reordered with respect to any following read or write.
不会发生reorder,所以构造总是在赋值之前。 13 楼 Silverside 2011-08-08 jilen 写道skzr.org 写道以下内容是我当时学习时整理的双检查:
1. 延迟实例化:使用正确的双检查模式,需要new Instance的的必须如此操作
实例:
public static T getInstance() {
if (instance == null) {
synchronized (T) {
if (instance == null) instance = new T();
}
}
return instance;
}
问题: instance = new T(); 当new的时候,做了两个操作
第一步申请内存,并且把引用给instance(此时instance!=null)
第二步调用构造器,初始化数据
所以:其他线程可能使用了这个不完整的实例(虽然new已经分配了内存,从而instance!=null, 但可能此对象还在构造,所以说instance实例还不完整)
解决:
public static T getInstance() {
if (instance == null) {
synchronized (T) {
if (instance == null) {
T t = new T();
instance = t;//<----解决办法
}
}
}
return instance;
}
注意:其他非instacne = new T()这样的,可以不用这么处理,比如: instance = existObj.getT();也就是任何非new的都不会出问题
我想你可能有些误解 Object t = new Object();这个表达式做文法分析的时候很显然是先构造后赋值的。之所以出现先赋值后构造,是编译器或者cpu指令优化(smp)才出现的偶然情况,而且发生之概率也是很低的。如果编译器发现构造器没有抛出任何异常,也没有任何同步,则可能因为优化指令等原因进行reorder,打乱赋值和初始化顺序。即使编译器指令正常,现代CPU也可能会在这些指令执行时reorder造成乱序。我想你的fix不能真的fix这个问题。
这个时候构造器会报什么异常呢?