以下代码片段来自 Effective Java 2nd Edition Double Checked Locking
//Double-check idiom for lazy initialization of instance fields
private volatile FieldType field;
FieldType getField() {
FieldType result = field;
if (result == null) { // First check (no locking)
synchronized(this) {
result = field;
if (result == null)// Second check (with locking)
field = result = computeFieldValue();
}
}
return result;
}
据我所知,双重检查锁定的主要问题是在第二次检查锁定中重新排序,这样其他线程可能会看到字段/结果的值已设置,实际上可能仍在执行中。为避免这种情况,我们将字段引用设置为易变的,以保证可见性和重新排序。
但这也可以通过下面的代码实现
private FieldType field; // non volatile
private volatile boolean fence = false;
FieldType getField() {
if (field == null) { // First check (no locking) // no volatile read
synchronized(this) { // inside synch block no problem of visibilty will latest //value of field
if (field == null) {// Second check (with locking)
Object obj = computeFieldValue();
fence = true; // any volatile write will take. this will make sure statements are //not reorder with setting field as non null.
field = (FieldType)obj; // this will be only set after computeFieldValue has been //completed fully
}
}
}
return field;
}
因此在初始化完成后,没有线程需要进行 volatile 读取或同步开销。请 看看我的假设是否正确?
最佳答案
"A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field."
您没有阅读 fence
更新后的变量,因此更新 fence
的线程之间没有“先发生”关系和任何第二个线程。这意味着不能保证第二个线程看到 field
的更新。第一个线程创建的变量。
简而言之,您的“改进”代码是双重检查锁定的错误实现。
关于java - 这是没有 volatile 和同步开销的更好版本的 Double Check Locking,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17169145/