ロジックは非常に簡単です。
Foo foo = cache.get();
if (isUpToDate(foo)) {
return foo;
} else {
foo = getUpdatedFoo(); // slow or expensive
cache.put(foo);
return foo;
}
ただし、確認したいのは
getUpdatedFoo()
一度に 1 つのスレッドのみを呼び出す- スレッド A が既に を呼び出している場合
getUpdatedFoo()
、スレッド B はそれを呼び出さず、スレッド A の結果を待つだけです。
おそらく、JCiP の Memoizer パターンに基づいて何かをまとめることができますが、もっと簡単な方法があると思います-おそらく Guava CacheBuilder を使用しますか? ただし、その方法はすぐにはわかりません。
更新:以下の FrankPL の回答に従って、二重チェックのロック パターンを実装しました。
Foo foo = cache.get();
if (!isUpToDate(foo)) {
lock.lock(); // Will block if some other thread is refreshing
try {
// See if some other thread already refreshed for us
foo = cache.get();
if (!isUpToDate(foo)) {
// guess not, we'll refresh it ourselves
foo = getUpdatedFoo();
cache.put(foo);
}
} finally {
lock.unlock();
}
}
return foo;