web-dev-qa-db-ja.com

javaでLRUキャッシュを使用するのが簡単でシンプル

実装は簡単ですが、すでに存在するものを再利用したいと思います。

解決したい問題は、さまざまなページ、ロールなどの構成を(XMLからキャッシュしたいので)読み込むことです。そのため、入力の組み合わせは非常に大きくなる可能性があります(ただし99%ではそうなりません)。この1%を処理するために、キャッシュに最大数のアイテムが必要です...

Apache commonsでorg.Apache.commons.collections.map.LRUMapを見つけたので、問題ないように見えますが、何か他のものもチェックしたいことを知っています。推奨事項はありますか?

62
Juraj

LinkedHashMap (Java 1.4+)を使用できます:

// Create cache
final int MAX_ENTRIES = 100;
Map cache = new LinkedHashMap(MAX_ENTRIES+1, .75F, true) {
    // This method is called just after a new entry has been added
    public boolean removeEldestEntry(Map.Entry eldest) {
        return size() > MAX_ENTRIES;
    }
};

// Add to cache
Object key = "key";
cache.put(key, object);

// Get object
Object o = cache.get(key);
if (o == null && !cache.containsKey(key)) {
    // Object not in cache. If null is not a possible value in the cache,
    // the call to cache.contains(key) is not needed
}

// If the cache is to be used by multiple threads,
// the cache must be wrapped with code to synchronize the methods
cache = (Map)Collections.synchronizedMap(cache);
98
Guido

これは古い質問ですが、後世のために ConcurrentLinkedHashMap をリストしたいと思いました。これは LRUMap とは異なり、スレッドセーフです。使い方はとても簡単です:

ConcurrentMap<K, V> cache = new ConcurrentLinkedHashMap.Builder<K, V>()
    .maximumWeightedCapacity(1000)
    .build();

また、ドキュメントにはいくつかの優れた examples があり、LRUキャッシュをアイテム数ベースではなくサイズベースにする方法などがあります。

27
Bobby Powers

最適な数の要素をメモリに保持できる実装を次に示します。

ポイントは、MRUオブジェクトにLinkedHashMapとLRUオブジェクトにWeakHashMapの組み合わせを使用しているため、現在使用されているオブジェクトを追跡する必要がないことです。そのため、キャッシュ容量はMRUサイズに加えて、GCで保持できるものになります。オブジェクトがMRUから落下するたびに、GCがオブジェクトを保持している限り、オブジェクトはLRUに移動します。

public class Cache<K,V> {
final Map<K,V> MRUdata;
final Map<K,V> LRUdata;

public Cache(final int capacity)
{
    LRUdata = new WeakHashMap<K, V>();

    MRUdata = new LinkedHashMap<K, V>(capacity+1, 1.0f, true) {
        protected boolean removeEldestEntry(Map.Entry<K,V> entry)
        {
            if (this.size() > capacity) {
                LRUdata.put(entry.getKey(), entry.getValue());
                return true;
            }
            return false;
        };
    };
}

public synchronized V tryGet(K key)
{
    V value = MRUdata.get(key);
    if (value!=null)
        return value;
    value = LRUdata.get(key);
    if (value!=null) {
        LRUdata.remove(key);
        MRUdata.put(key, value);
    }
    return value;
}

public synchronized void set(K key, V value)
{
    LRUdata.remove(key);
    MRUdata.put(key, value);
}
}
13
botek

私も同じ問題を抱えていて、良いライブラリが見つかりませんでした...自分で作成しました。

simplelrucacheは、TTLをサポートする、スレッドセーフで非常にシンプルな非分散LRUキャッシングを提供します。2つの実装を提供します。

  • ConcurrentLinkedHashMapに基づく並行
  • LinkedHashMapに基づいて同期

あなたはそれを見つけることができます こちら

1
Daimon

ここ は、Javaで非常にシンプルで使いやすいLRUキャッシュです。短くてシンプルですが、生産品質です。コードは説明されており(README.mdを参照)、いくつかの単体テストがあります。

1
Barak