4

キャッシュのデータをロードするメソッドが一括呼び出しであるユース ケースがありますが、getAll を使用してキャッシュからデータを取得することは決してありません。単一の loadAll で複数の同時 get all ブロッ​​クを実行する方法はありますか? 個々のキーが異なるキーを取得して、データ ソースへの複数の呼び出しが発生することは望ましくありません。

cache.get(key1); // missing entry, starts refresh
cache.get(key2); // separate thread, already getting reloaded due to key1 miss

LocalCache を調べた後、データ アクセサーのローカル キャッシュのようなものを使用して独自の同期を実装する必要があると思います。呼び出しが成功したら、単一の割り当てステートメントでローカル コピーを更新します。

Guava のキャッシュ ライブラリに何か不足していますか?

編集:

以下のようなものを検討しています。loadAllただし、終了中に古いデータを返し続ける可能性があります。すべてが でブロックされload、最初のリクエストのみがloadAll続行されることを望みます。

public class DataCacheLoader extends CacheLoader<String, Double>
{
    private final Cache<String, Double> cache;
    private ConcurrentMap<String, Double> currentData;
    private final AtomicBoolean isloading;

    public DataCacheLoader( final Cache<String, Double> cache )
    {
        this.cache = cache;
        isLoading = new AtomicBoolean( false );
    }

    @Override
    public Double load( final String key ) throws Exception
    {
        if ( isLoading.compareAndSet( false, true ) )
        {
            cache.putAll( loadAll( Lists.newArrayList( key ) ) ) );
        }
        return currentData.get( key );
    }

    @Override
    public Map<String, Double> loadAll(Iterable<? extends String> keys) throws Exception
    {
        currentData = source.getAllData();
        return currentData;
    }
}
4

1 に答える 1

10

これがそのトリックを行うソリューションです。アイデアは、個々のキーをそれぞれキャッシュする代わりに、単一の固定キーでマップ全体をキャッシュするというものです。1 つの欠点は、基になるマップの個々の部分を期限切れにできないことです (少なくとも簡単ではありません) が、これは必須ではない場合があります。

class MyCache {
  private static final Object KEY = new Object();
  private final LoadingCache<Object, Map<String, Double>> delegate = 
      new CacheBuilder()
      // configure cache
          .build(new CacheLoader<Object, Map<String, Double>>() {
             public Map<String, Double> load(Object key) {
               return source.load();
             }
          };
  double get(String key) {
    return cache.get(KEY).get(key);
  }
}
于 2013-08-16T11:06:27.850 に答える