`
java-mans
  • 浏览: 11444967 次
文章分类
社区版块
存档分类
最新评论

java 的double-check locking

 
阅读更多

《Java与模式》在讲Lazy Singleton时,提到在c++单例中广泛使用的double-checl locking,在java中确实无效的:
“在Java编译器中,LazySingleton类的初始化与m_instance变量赋值的顺序不可预料。如果一个线程在没有同步化的条件下读取m_instance引用,并调用这个对象的方法的话,可能会发现对象的初始化过程尚未完成,从而造成崩溃。”

public classLazySingleton {
private staticLazySingleton m_instance = null;

privateLazySingleton() {
}

public staticLazySingleton getInstance() {
if(m_instance==null) {
synchronized (LazySingleton.class) {
if(m_instance==null) {
m_instance=new LazySingleton();
}
}
}
returnm_instance;
}
}

这段话是说,是jvm执行时会对便以后的字节码重排序(reordering),最坏的情况下,当m_instance被赋值以后(不为null,过了里面的那层检查),LazySingleton类其实还没有完成初始化,那么对m_instance中成员的访问就会导致错误。当然这种是极少发生的,在这个问题被发现之前java的double-check locking也曾大行其道。
阎宏写《Java与模式》的时候java还在1.4的版本。当java1.5发布以后,情况发生了一点改变。java的double check也是可行的了。只要LazySingleton的所有instance field都是immutable的话,就能保证成功了。在Java5之后,有一个所谓的“happens-before”的概念,在每一个构造函数结束的地方都有一个freeze动作,在构造函数返回前,所有的final成员变量都要完成初始化。使用volatile来修饰static的m_instance也可以保证成功,然而一些jvm并没有正确实现volatile语义,所以这种发放还不是那么保险。官方的说法是:
"In JVMs prior to 1.5, volatile would not ensure that it worked (your mileage may vary). Under the new memory model, making the instance field volatile will "fix" the problems with double-checked locking, because then there will be a happens-before relationship between the initialization of the Something by the constructing thread and the return of its value by the thread that reads it."

按照java专家们的习惯,java中会出问题的东西,一定是不好的东西。JSR 166专家组说,double-checked locking是一种不好的发明,现在已经被广泛废弃。替代是Lazy initialization holder,提供了同样的好处,也更容易理解。Effective Java中有个例子
public classFoo {
private static classFooHolder {
static finalFoo foo=new Foo();
}
public staticFoo getFoo() {
returnFooHolder.foo;
}
}
这是个很triky的方法,利用了jvm类加载时的特性,第一次使用FooHolder时才进行初始化。不得不承认,看起来确实比double-checked locking简单舒服一些。


http://hi.baidu.com/%BA%FA%D2%E7%D1%F3/blog/item/24e14e4aeabd762b09f7ef81.html

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics