2012-03-15 57 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()。因此你会重新命名你的方法。