首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

Double Check Locking - Java并发

2012-12-18 
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这个问题。
这个时候构造器会报什么异常呢?

热点排行