使用双重检查成语重置延迟加载的字段

les*_*es2 5 java locking thread-safety double-checked-locking

考虑"对实例字段的延迟初始化进行双重检查":

// Item 71 in Effective Java copied from this interview with Bloch.
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;
}

我希望能够以安全的方式重置字段(强制它再次从数据库加载,在我的情况下).我假设我们可以通过重置方法来做到这一点:

void reset() {
   field = null;
}

这是重置场地的标准方法吗?安全吗?任何陷阱?我问,因为布洛赫发出了关于双重检查懒惰加载的以下警告:"成语非常快,但也很复杂和细腻,所以不要试图以任何方式修改它.只需复制和粘贴 - 通常这不是一个好主意,但在这里是合适的."

在此先感谢喜马拉雅山脉的Playa.

eri*_*son 4

是的,这是线程安全的。

同步块是为了防止多个线程不必要的调用computeFieldValue()。由于是 易失性的,因此和field中的访问都是有序的。resetgetField

如果第一次检查非空,getField则完成;result被返回。

否则,将获取锁,排除可能将该字段设置为非空的任何其他线程,但允许任何线程设置field为空。如果任何线程确实设置field为 null,则不应发生任何更改;这就是使线程进入同步块的条件。如果另一个线程在当前线程检查后已经获取了锁,并将该字段设置为非空值,则第二次检查将检测到这一点。