2012-03-15 85 views
1

我有下面的代碼,我試圖寫一個LRU緩存。我有一個跑步類,我正在運行緩存的隨機容量。但是,緩存大小超過容量。當我使FixLRU方法同步時,當緩存大小超過100時變得更加準確,但速度變慢。當我刪除同步關鍵字時,緩存變得不太準確。同步不起作用

任何想法如何使其正常工作?更準確?

import java.util.concurrent.ConcurrentHashMap; 

public abstract class Cache<TKey, TValue> implements ICache<TKey,TValue>{ 

    private final ConcurrentHashMap<TKey,TValue> _cache; 

    protected Cache() 
    { 
     _cache= new ConcurrentHashMap<TKey, TValue>(); 
    } 

    protected Cache(int capacity){ 
     _cache = new ConcurrentHashMap<TKey, TValue>(capacity); 
    } 

    @Override 
    public void Put(TKey key, TValue value) { 
     _cache.put(key, value); 
    } 

    @Override 
    public TValue Get(TKey key) { 
     TValue value = _cache.get(key); 

     return value; 
    } 

    @Override 
    public void Delete(TKey key) { 
     _cache.remove(key); 
    } 

    @Override 
    public void Purge() { 
     for(TKey key : _cache.keySet()){ 
      _cache.remove(key); 
     } 
    } 

    public void IterateCache(){ 

     for(TKey key: _cache.keySet()){ 
      System.out.println("key:"+key+" , value:"+_cache.get(key)); 
     } 

    } 

    public int Count() 
    { 
     return _cache.size(); 
    } 


} 


import java.util.concurrent.ConcurrentLinkedQueue; 

public class LRUCache<TKey,TValue> extends Cache<TKey,TValue> implements ICache<TKey, TValue> { 

    private ConcurrentLinkedQueue<TKey> _queue; 
    private int capacity; 
    public LRUCache(){ 
     _queue = new ConcurrentLinkedQueue<TKey>(); 
    } 

    public LRUCache(int capacity){ 
     this(); 
     this.capacity = capacity; 
    } 

    public void Put(TKey key, TValue value) 
    { 
     FixLRU(key); 

     super.Put(key, value); 
    } 

    private void FixLRU(TKey key) 
    { 
     if(_queue.contains(key)) 
     { 
      _queue.remove(key); 
      super.Delete(key); 
     } 

     _queue.offer(key); 

     while(_queue.size() > capacity){ 
      TKey keytoRemove =_queue.poll(); 
      super.Delete(keytoRemove); 
     } 
    } 

    public TValue Get(TKey key){ 

     TValue _value = super.Get(key); 

     if(_value == null){ 
      return null; 
     } 

     FixLRU(key); 

     return _value; 
    } 

    public void Delete(TKey key){ 

     super.Delete(key); 
    } 

} 

public class RunningLRU extends Thread{ 

    static LRUCache<String, String> cache = new LRUCache<String, String>(50); 

    public static void main(String [ ] args) throws InterruptedException{ 

     Thread t1 = new RunningLRU(); 
     t1.start(); 
     Thread t2 = new RunningLRU(); 
     t2.start(); 
     Thread t3 = new RunningLRU(); 
     t3.start(); 
     Thread t4 = new RunningLRU(); 
     t4.start(); 
     try { 
      t1.join(); 
      t2.join(); 
      t3.join(); 
      t4.join(); 
     } catch (InterruptedException e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 

     System.out.println(cache.toString()); 
     cache.IterateCache(); 
     System.out.println(cache.Count()); 

    } 

    @Override 
    public void run() { 
     for(int i=0;i<100000;i++) 
      cache.Put("test"+i, "test"+i); 
    } 

} 
+0

嘗試在FixLRU方法的主塊周圍使用synchronized(capacity){// code}。 – darijan 2012-03-15 12:04:46

回答

2

我會在添加條目後清理其他條目。這最大限度地減少了緩存將比你想要的更大的時間。您也可以觸發size()來執行清理。

任何想法如何使其正常工作?

您的測試是否反映了您的應用程序的行爲?當你沒有敲擊它時,緩存行爲可能正確(或者更接近它)。 ;)

如果此測試確實反映了您的應用程序行爲,那麼LRUCache可能不是最佳選擇。

+0

它工作正常,當我不hammmering它,即:單線程。當我使用同步。方法來修復後備隊列,它也能正常工作,但是當我刪除同步時,它會變慢。關鍵字來自方法,緩存大小超過它的容量。 – DarthVader 2012-03-15 12:00:22

+0

如果你在'put()'結尾處清理,它有多糟?鑑於你的能力可能是任意的,這個問題有多大? – 2012-03-15 12:05:24

+0

它是隨機的,因爲你會猜測。我只是想要它是精確的。我正在使用併發集合,但仍然存在這些問題。如果我使用併發集合並使用同步關鍵字,那麼有什麼意義?對。 – DarthVader 2012-03-15 12:10:09

2

你的問題似乎是你沒有使用同步版本的放置方法putIfAbsent()。如果你不使用它,ConcurrentHashMap的行爲就好像不是同步 - 就像一個普通的Map如HashMap一樣。

當你使用它,你必須繼續只使用返回價值,所以你Put()方法不正確的簽名(它應該返回TValue),以支持併發。你需要重新設計你的界面。

此外,在Java領域,與.Net領域不同,我們將我們的方法命名爲帶有小寫字母的主題,例如put(),而不是Put()。因此你會重新命名你的方法。