下面的代码片段来自 Effective Java 2nd Edition Double Checked Locking
// 仔细检查实例字段延迟初始化的习惯用法
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;
}
据我所知,双重检查锁定的主要问题是第二次检查锁定内部的重新排序,以便其他线程可能会看到已设置的字段/结果的值实际上可能仍在执行中。为了避免这种情况,我们将字段的引用设置为 volatile 以保证可见性和重新排序。
但这也可以通过下面的代码来实现
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;
}
因此,在完成初始化后,没有线程需要进行易失性读取或同步开销。请看看我的假设是否正确?