2008-10-22 23 views
52

Uygulamanın basit olduğunu biliyorum, ancak zaten var olan bir şeyi yeniden kullanmak istiyorum.Kolay, kullanımı kolay LRU önbellek kullanımı java

Sorunu çözmek istediğim, farklı sayfalar, roller için (XML'den önbelleğe almak istiyorum) yapılandırma yüklüyorum, bu yüzden girişlerin kombinasyonu çok fazla büyüyebilir (ancak% 99'unda olmaz) . Bu% 1'i işlemek için, önbellekteki bazı maksimum öğelerin sayısını istiyorum ...

Biliyorum apache commons'ta org.apache.commons.collections.map.LRUMap buldum ve iyi görünüyor ama ayrıca başka bir şey kontrol edin. Herhangi bir tavsiye?

+0

@Suporwski Bu sorunu nasıl çözdünüz? – Hunt

+0

@Hunt Commons'tan LRUMap var – Juraj

+0

Çok benzer bir soru da [burada] (http://stackoverflow.com/q/221525/2032064) – Mifeet

cevap

87

Bir LinkedHashMap (Java 1.4+) kullanabilirsiniz:

// 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); 
+5

Commons koleksiyonlarından LRUMap iyi bir seçimdir. –

+1

Tamam, bu yüzden LRUMap kullanmaya karar verdim. – Juraj

+0

Sadece bir not - her iki bağlantınız da aynı örneğe gidiyor, bence eski LHM javadoc olmalı? – JeeBee

21

Bu eski bir sorudur, ama gelecek kuşaklar için ben LRUMap aksine parçacığı güvenli olan ConcurrentLinkedHashMap listelemek istedi. Kullanımı oldukça kolaydır:

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

Ve dokümantasyon LRU önbellek boyutu tabanlı yerine sayı-of-kalemleri dayalı iyi şekilde nasıl gibi bazı iyi examples sahiptir.

+5

[Kafein] (https://github.com/ben-manes/caffeine), daha hızlı olan (https://github.com/ben-manes/caffeine/wiki/Benchmarks) ve Java 8 yeniden yazımdır. daha birçok özellik sunuyor (https://github.com/ben-manes/caffeine/wiki/Cache). –

1

Aynı problem yaşadım ve iyi bir kütüphane bulamadım ... kendi kendimi yarattım.

simplelrucache iş parçacığı sağlar, çok basit, dağıtılmamış TTL desteği ile LRU önbelleğe alma. Bu ConcurrentLinkedHashMap

  • dayalı iki uygulamaları

    • Eşzamanlı sağlayan Bunu here bulabilirsiniz LinkedHashMap

    dayalı eşitlenen.

  • +0

    Kütüphanenizi Maven Central'da serbest bırakabilir misiniz? –

    +1

    Sürüm 1.0 şimdi ortada olmalı :) – Daimon

    1

    Here Java'da çok basit ve kullanımı kolay bir LRU önbellekidir. Kısa ve basit olmasına rağmen, üretim kalitesidir. Kod açıklanmıştır (README.md'ye bakın) ve bazı birim testleri vardır.

    11

    En uygun sayıda öğeyi bellekte tutmamı sağlayan benim uygulamam.

    Önemli olan nokta, MRU nesneleri için bir LinkedHashMap ile LRU nesneleri için bir WeakHashMap kombinasyonunun kullanılmasından bu yana hangi nesnelerin kullanılmakta olduğunun izlenmesi gerekmemesidir. Dolayısıyla, önbellek kapasitesi MRU boyutundan daha az değil ve GC ne yapmamı sağlıyorsa onu korusun. Nesneler MRU'dan düştüğünde, GC'nin sahip olduğu sürece LRU'ya giderler.

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

    Bu şık bir yaklaşım. Bu nedenle, LRU önbelleği, boyutu sınırlı MRU önbelleğinden zaman aşımına uğramış olan eşyaları depolar. Bir yazılım 2. seviye önbellek gibi. Güzel! –

    +0

    Grok'a bir dakika sürdü ama çok havalı! – benkc

    +0

    LRUdata'da veri bulunmuş, ancak MRUdata'da eksik olan veriler varsa, önbellek boyutunun artırılması hakkında uygulama günlüğüne yararlı bir uyarı/ipucu verilebilir. –