【问题标题】:LRU Cache Implementation in JavaJava中的LRU缓存实现
【发布时间】:2015-07-19 17:33:24
【问题描述】:

我看过下面的代码,觉得addElement方法的实现有一个无用的while循环。因为已经有一个写锁,所以它不应该碰巧有超过 size+1 的元素。 那么为什么 addElement 方法要删除元素直到它得到这个条件 真的

while(concurrentLinkedQueue.size() >=maxSize)

任何关于这个的指针都会很棒。

这是实现:

public class  LRUCache<K,V> {

    private  ConcurrentLinkedQueue<K> concurrentLinkedQueue = new ConcurrentLinkedQueue<K>();

    private  ConcurrentHashMap<K,V> concurrentHashMap = new ConcurrentHashMap<K, V>();

    private ReadWriteLock readWriteLock = new ReentrantReadWriteLock();

    private Lock readLock = readWriteLock.readLock();

    private Lock writeLock = readWriteLock.writeLock();

    int maxSize=0;

    public LRUCache(final int MAX_SIZE){
        this.maxSize=MAX_SIZE;
    }

    public V getElement(K key){

        readLock.lock();
        try {
        V v=null;
          if(concurrentHashMap.contains(key)){
              concurrentLinkedQueue.remove(key);
              v= concurrentHashMap.get(key);
                concurrentLinkedQueue.add(key);
          }


        return v;
        }finally{
            readLock.unlock();
        }
    }

    public V removeElement(K key){
         writeLock.lock();
         try {
        V v=null;
        if(concurrentHashMap.contains(key)){
        v=concurrentHashMap.remove(key);
            concurrentLinkedQueue.remove(key);
        }

        return v;
         } finally {
             writeLock.unlock();
         }
    }

    public V addElement(K key,V value){
        writeLock.lock();
        try {
        if(concurrentHashMap.contains(key)){
             concurrentLinkedQueue.remove(key);
        }
        while(concurrentLinkedQueue.size() >=maxSize){
             K queueKey=concurrentLinkedQueue.poll();
             concurrentHashMap.remove(queueKey);
        }
        concurrentLinkedQueue.add(key);
        concurrentHashMap.put(key, value);

        return value;
        } finally{
            writeLock.unlock();
        }
    }
}

【问题讨论】:

  • 仅供参考:ConcurrentLinkedQueue#size 需要全面扫描,而 ConcurrentHashMap#size 会被跟踪。您的实现是 O(n),而有效的实现是 O(1)。您可能有兴趣阅读并发 LRU 缓存的design
  • 您可以在以下链接找到有效的解决方案:stackoverflow.com/questions/6398902/…
  • 既然线程安全是通过使用锁来保证的,我相信没有必要使用并发版本的map和queue。这只是开销

标签: java multithreading caching concurrency lru


【解决方案1】:

我想,这里的重点是您需要检查 LRU 是否处于最大尺寸。这里的检查不是(map.size()> maxSize),而是“>=”。现在,您可能可以将其替换为“if (map.size() == maxSize) {...}” - 在理想情况下,它应该做完全相同的事情。

但在不太理想的条件下,如果出于某种原因,有人在未检查的情况下将 EXTRA 条目放入映射中,那么使用此代码,映射将永远不会再缩小,因为 if 条件永远不会真的。

所以 - 为什么不用“while”和 ">=" 而不是 "if" 和 "=="?相同数量的代码,加上更强大的“意外”条件。

【讨论】:

    【解决方案2】:

    一个简单的 LRU 缓存实现如下,只有在调整最大大小时才需要 while 循环,而对于原始操作则不需要:

    • 在放置过程中,移除多余的元素。
    • 在获取期间,将元素移动到顶部。

    原始操作将是一次性的。然后,您可以围绕此数据结构使用普通同步或读写锁。

    当使用读写锁时,谁先来的公平则更多是使用的读写锁的问题,而不是 LRU 缓存本身的问题。

    Here 是一个示例实现。

    【讨论】:

      【解决方案3】:

      这并没有错,只是为了防止意外修改的安全。您可以在条件语句中检查 concurrentLinkedQueue.size() == maxSize 是否相等。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-11-03
        • 2021-03-05
        • 2010-09-18
        • 1970-01-01
        • 2015-02-13
        • 1970-01-01
        • 1970-01-01
        • 2011-09-17
        相关资源
        最近更新 更多