据我了解,这是Java中双重检查锁定模式的正确实现(自Java 5以来):
class Foo {
private volatile Bar _barInstance;
public Bar getBar() {
if (_barInstance == null) {
synchronized(this) { // or synchronized(someLock)
if (_barInstance == null) {
Bar newInstance = new Bar();
// possible additional initialization
_barInstance = newInstance;
}
}
}
return _barInstance;
}
}
我想知道没有
volatile
是否会是一个严重的错误,还是只是一种轻微的缺陷,假设_barInstance
只通过getBar
访问。我的想法是:同步引入了“发生在-之前”的关系。初始化
_barInstance
的线程将其值写入主内存并离开同步块。因此,即使_barInstance
不是volatile
,也不会出现双重初始化:其他线程在其本地副本中具有null
(在第一次检查时得到true
),但必须在进入同步块后从主内存中读取新值(在第二次检查时得到false
并且不进行重新初始化)。因此,唯一的问题就是每个线程都会获得多余的一次锁定。据我所知,这在CLR中是正确的,而且我相信在JVM中也是正确的。我对吗?
谢谢。
volatile
很重要”和“不是线程安全”的说法,没有解释。我真的想详细了解这个情况 :) - Ivan Yurchenko_barInstance
并且后续线程可以看到_barInstance
已初始化之前执行。当它们看到它不是null
时,它们不会获取锁并且 happens-before…嗯,就是没有发生 :) 然后它们使用未初始化的对象。另一方面,当_barInstance
是volatile
的时候,写和读始终保持 happens-before。正确吗? - Ivan Yurchenko