1

ロジックは非常に簡単です。

Foo foo = cache.get();
if (isUpToDate(foo)) {
    return foo;
} else {
    foo = getUpdatedFoo(); // slow or expensive
    cache.put(foo);
    return foo;
}

ただし、確認したいのは

  1. getUpdatedFoo()一度に 1 つのスレッドのみを呼び出す
  2. スレッド 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;
4

2 に答える 2

0

おそらく、読み取り/書き込みロック ( http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html )を検討できます。サンプルコードを以下に示します。

rwlock.readLock().lock();
Foo foo = cache.get();
if(isUpToDate(foo)) {
    rwlock.readLock.unlock();
    return foo;
} else {
    rwlock.readLock.unlock();
    rwlock.writeLock.lock();
    // recheck if updated
    Foo foo = cache.get();
    if(isUpToDate(foo)) {
        rwlock.writeLock.unlock();
        return foo;
    } else {
        foo = getUpdatedFoo();
        cache.put(foo);
        rwlock.writeLock.unlock();
        return foo;
    }
}
于 2013-08-23T23:00:09.063 に答える