1

The logic is pretty straightforward:

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

However, I want to make sure that

  1. only one thread calls getUpdatedFoo() at a time
  2. if thread A is already calling getUpdatedFoo(), thread B doesn't call it, instead just waiting for thread A's results

I could probably cobble together something based on the Memoizer pattern from JCiP, but I suspect there's a simpler way -- possibly using Guava CacheBuilder? Not immediately obvious how, though.


Update: Implemented a double-checked locking pattern per FrankPL's answer below:

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 回答
0

有关您可以使用的双重检查锁定模式,请参阅http://en.wikipedia.org/wiki/Double-checked_locking 。而不是new Helper()代码示例中使用的,使用您的getUpdatedFoo().

于 2013-08-23T20:49:15.413 回答