2013-08-23 4 views
1

Логика очень проста:поточно-обновление кэшированных ресурса

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

Однако, я хочу, чтобы убедиться, что

  1. только один поток вызывает getUpdatedFoo() в то время
  2. если нить A уже звонит getUpdatedFoo(), нить B не назовите его, вместо этого просто ждите нити A's results

Возможно, я смогу собрать что-то, основанное на шаблоне Memoizer от JCiP, но я подозреваю, что есть более простой способ - возможно, с помощью Guava CacheBuilder? Не сразу очевидно, как, однако.


Update: Реализована блокировка с двойной проверкой шаблон на FrankPL's answer ниже:

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; 
+0

Вы можете указать один поток, чтобы обновить кеш в фоновом режиме. – Gray

+0

Вы считаете [ehcache] (http://ehcache.org/) - это действительно так просто, как кажется. – OldCurmudgeon

+0

@ Gray Я мог бы, но до тех пор, пока потоки клиентов будут блокировать ожидание этого потока, я бы предпочел, чтобы один из них выполнял эту работу. –

ответ

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; 
    } 
} 
Смежные вопросы